From bae3f61a4e61d4f2e300d3cdc243cd2e7ec5c34c Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 7 Jun 2021 08:11:06 +0900 Subject: [PATCH 1/4] wxMediaCtrl wayland support: pass wl_display to gstreamer gstreamer creates a new connection to the wayland display by default, and gst_video_overlay_set_window_handle() only works if both the parent surface (part of the gtk window) and the gstreamer surface are on the same display, so we need to tell gstreamer about our wl_display when it asks --- src/unix/mediactrl_gstplayer.cpp | 38 ++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/unix/mediactrl_gstplayer.cpp b/src/unix/mediactrl_gstplayer.cpp index 9b301985be..355e22a014 100644 --- a/src/unix/mediactrl_gstplayer.cpp +++ b/src/unix/mediactrl_gstplayer.cpp @@ -217,7 +217,35 @@ static void end_of_stream_callback(GstPlayer * WXUNUSED(player), wxGStreamerMedi { be->EndOfStream(); } + +#define GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE "GstWaylandDisplayHandleContextType" +static GstBusSyncReply bus_sync_handler(GstBus * WXUNUSED(bus), GstMessage* msg, gpointer WXUNUSED(user_data)) +{ + const gchar *type = NULL; + + if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT && + gst_message_parse_context_type(msg, &type) && + !g_strcmp0 (type, GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) + { + GstContext *context = gst_context_new (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE, TRUE); + GstStructure *s = gst_context_writable_structure(context); + wxDisplayInfo display_info = wxGetDisplayInfo(); + /* On wayland we need to explicitely transmit the display handle to gstreamer, + * but attribute expected depends on which video sink got selected. + * "display" will likely remain as the normal way of doing for gst 1.19+ + * but there is no harm in setting both for compatibility + */ + gst_structure_set(s, "handle", G_TYPE_POINTER, display_info.dpy, NULL); + gst_structure_set(s, "display", G_TYPE_POINTER, display_info.dpy, NULL); + gst_element_set_context(GST_ELEMENT(msg->src), context); + + return GST_BUS_DROP; + } + + return GST_BUS_PASS; } +} + bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent, wxWindowID id, @@ -337,6 +365,16 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent, m_video_renderer = gst_player_video_overlay_video_renderer_new(window_handle); m_player = gst_player_new(m_video_renderer, gst_player_g_main_context_signal_dispatcher_new(NULL)); + wxDisplayInfo info = wxGetDisplayInfo(); + if (info.type == wxDisplayWayland) + { + // wayland needs a specific handler to pass display to gstreamer + GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(gst_player_get_pipeline(m_player))); + gst_bus_add_signal_watch(bus); + gst_bus_set_sync_handler(bus, bus_sync_handler, this, NULL); + gst_object_unref(bus); + } + g_signal_connect(m_player, "video-dimensions-changed", G_CALLBACK(video_dimensions_changed_callback), this); g_signal_connect(m_player, "state-changed", G_CALLBACK(state_changed_callback), this); g_signal_connect(m_player, "end-of-stream", G_CALLBACK(end_of_stream_callback), this); From b16aba57b1104ac20f090f1072ce41468865888a Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 7 Jun 2021 08:11:26 +0900 Subject: [PATCH 2/4] wxMediaCtrl wayland support: place window where we want it without this call gstreamer + gtk wayland would just draw the video over the whole window. There might be a better way to do that --- src/unix/mediactrl_gstplayer.cpp | 40 +++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/unix/mediactrl_gstplayer.cpp b/src/unix/mediactrl_gstplayer.cpp index 355e22a014..ef0ddd3b95 100644 --- a/src/unix/mediactrl_gstplayer.cpp +++ b/src/unix/mediactrl_gstplayer.cpp @@ -175,9 +175,25 @@ expose_event_callback(GtkWidget* widget, GdkEventExpose* event, wxGStreamerMedia extern "C" { static void realize_callback(GtkWidget* widget, wxGStreamerMediaBackend* be) { - gst_player_video_overlay_video_renderer_set_window_handle(GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer), - wxGtkGetIdFromWidget(widget) - ); + gst_player_video_overlay_video_renderer_set_window_handle( + GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer), + wxGtkGetIdFromWidget(widget) + ); +#ifdef __WXGTK3__ + GdkWindow* window = gtk_widget_get_window(widget); + if (strcmp("GdkWaylandWindow", g_type_name(G_TYPE_FROM_INSTANCE(window))) == 0) + { + // on wayland we need to place the video + int x, y; + GtkAllocation allocation; + gdk_window_get_origin(window, &x, &y); + gtk_widget_get_allocation(widget, &allocation); + gst_player_video_overlay_video_renderer_set_render_rectangle( + GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer), + x, y, allocation.width, allocation.height + ); + } +#endif GtkWidget* w = be->GetControl()->m_wxwindow; #ifdef __WXGTK3__ g_signal_connect(w, "draw", G_CALLBACK(draw_callback), be); @@ -491,10 +507,22 @@ wxLongLong wxGStreamerMediaBackend::GetDuration() void wxGStreamerMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(w), int WXUNUSED(h)) { - /* Nothing to be done here, at least for GTK+. For other toolkits we might - * have to call - * gst_player_video_overlay_video_renderer_set_render_rectangle() here + /* GTK+ on X11 does not require explicitely setting the video size. + * Other toolkits might need to do something similar to GTK wayland too. */ +#ifdef __WXGTK3__ + GdkWindow* window = gtk_widget_get_window(m_ctrl->m_wxwindow); + if (window && strcmp("GdkWaylandWindow", g_type_name(G_TYPE_FROM_INSTANCE(window))) == 0) { + int x, y; + GtkAllocation allocation; + gdk_window_get_origin(window, &x, &y); + gtk_widget_get_allocation(m_ctrl->m_wxwindow, &allocation); + gst_player_video_overlay_video_renderer_set_render_rectangle( + GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(m_video_renderer), + x, y, allocation.width, allocation.height + ); + } +#endif } wxSize wxGStreamerMediaBackend::GetVideoSize() const From 0080aa60863f3631788951c9bcf9b852172a2060 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Tue, 8 Jun 2021 10:22:51 +0900 Subject: [PATCH 3/4] wxMediaCtrl wayland support: disable xvimagesink on wayland gstreamer is known to crash on xvimagesink if the main window is wayland-native and DISPLAY is set: try to make it not load. Also do the same for ximagesink just in case. --- src/unix/mediactrl_gstplayer.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/unix/mediactrl_gstplayer.cpp b/src/unix/mediactrl_gstplayer.cpp index ef0ddd3b95..606ac7271f 100644 --- a/src/unix/mediactrl_gstplayer.cpp +++ b/src/unix/mediactrl_gstplayer.cpp @@ -389,6 +389,23 @@ bool wxGStreamerMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent, gst_bus_add_signal_watch(bus); gst_bus_set_sync_handler(bus, bus_sync_handler, this, NULL); gst_object_unref(bus); + + // xvimagesink is known to crash gstreamer with a wayland window + // if display is set; try to make it not load. + GstPluginFeature *feature; + feature = gst_registry_find_feature( + gst_registry_get(), "xvimagesink", GST_TYPE_ELEMENT_FACTORY + ); + if (feature) { + gst_plugin_feature_set_rank(feature, GST_RANK_NONE); + } + // same for ximagesink + feature = gst_registry_find_feature( + gst_registry_get(), "ximagesink", GST_TYPE_ELEMENT_FACTORY + ); + if (feature) { + gst_plugin_feature_set_rank(feature, GST_RANK_NONE); + } } g_signal_connect(m_player, "video-dimensions-changed", G_CALLBACK(video_dimensions_changed_callback), this); From e3db863a0e767f248a13f3d8f14e185bee3b82d8 Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Wed, 9 Jun 2021 15:38:24 +0900 Subject: [PATCH 4/4] wxMediaCtrl wayland support: resize video in expose_event_callback the Move handler apparently misses some resize events, so move the gst_player_video_overlay_video_renderer_set_render_rectangle call to expose_event_callback. This is kept as a separate commit because it would be more efficient to keep it in Move once we can catch that initial size change, so this commit can get reverted then. --- src/unix/mediactrl_gstplayer.cpp | 37 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/unix/mediactrl_gstplayer.cpp b/src/unix/mediactrl_gstplayer.cpp index 606ac7271f..f8f84374e7 100644 --- a/src/unix/mediactrl_gstplayer.cpp +++ b/src/unix/mediactrl_gstplayer.cpp @@ -142,7 +142,24 @@ expose_event_callback(GtkWidget* widget, GdkEventExpose* event, wxGStreamerMedia // GST Doesn't redraw automatically while paused // Plus, the video sometimes doesn't redraw when it looses focus // or is painted over so we just tell it to redraw... - gst_player_video_overlay_video_renderer_expose(GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer)); + gst_player_video_overlay_video_renderer_expose( + GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer) + ); +#ifdef __WXGTK3__ + GdkWindow* window = gtk_widget_get_window(widget); + if (strcmp("GdkWaylandWindow", g_type_name(G_TYPE_FROM_INSTANCE(window))) == 0) + { + // on wayland we need to place the video + int x, y; + GtkAllocation allocation; + gdk_window_get_origin(window, &x, &y); + gtk_widget_get_allocation(widget, &allocation); + gst_player_video_overlay_video_renderer_set_render_rectangle( + GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(be->m_video_renderer), + x, y, allocation.width, allocation.height + ); + } +#endif } else { @@ -524,22 +541,10 @@ wxLongLong wxGStreamerMediaBackend::GetDuration() void wxGStreamerMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int WXUNUSED(w), int WXUNUSED(h)) { - /* GTK+ on X11 does not require explicitely setting the video size. - * Other toolkits might need to do something similar to GTK wayland too. + /* Nothing to be done here, at least for GTK+. For other toolkits we might + * have to call + * gst_player_video_overlay_video_renderer_set_render_rectangle() here */ -#ifdef __WXGTK3__ - GdkWindow* window = gtk_widget_get_window(m_ctrl->m_wxwindow); - if (window && strcmp("GdkWaylandWindow", g_type_name(G_TYPE_FROM_INSTANCE(window))) == 0) { - int x, y; - GtkAllocation allocation; - gdk_window_get_origin(window, &x, &y); - gtk_widget_get_allocation(m_ctrl->m_wxwindow, &allocation); - gst_player_video_overlay_video_renderer_set_render_rectangle( - GST_PLAYER_VIDEO_OVERLAY_VIDEO_RENDERER(m_video_renderer), - x, y, allocation.width, allocation.height - ); - } -#endif } wxSize wxGStreamerMediaBackend::GetVideoSize() const