Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Wayland support in OpenGL video output #36

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions plugins/actions/preferences/videoplayerpage.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@

#include "preferencepage.h"

#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif

class ComboBoxOutput : public Gtk::ComboBox {
class Column : public Gtk::TreeModel::ColumnRecord {
public:
Expand Down Expand Up @@ -111,18 +115,23 @@ class VideoPlayerPage : public PreferencePage {
#endif

// video output
m_comboVideoOutput->append_output(_("Autodetect"), "autovideosink");
m_comboVideoOutput->append_output(_("X Window System (X11/XShm/Xv)"),
"xvimagesink");
m_comboVideoOutput->append_output(_("X Window System (No Xv)"),
"ximagesink");
m_comboVideoOutput->append_output(_("SDL - Simple DirectMedia Layer"),
"sdlvideosink");
m_comboVideoOutput->append_output(_("GConf"), "gconfvideosink");
m_comboVideoOutput->append_output(_("OpenGL"), "glimagesink");
#ifdef GDK_WINDOWING_WAYLAND
if (!GDK_IS_WAYLAND_DISPLAY(get_display()->gobj()))
#endif
{
m_comboVideoOutput->append_output(_("Autodetect"), "autovideosink");
m_comboVideoOutput->append_output(_("X Window System (X11/XShm/Xv)"),
"xvimagesink");
m_comboVideoOutput->append_output(_("X Window System (No Xv)"),
"ximagesink");
m_comboVideoOutput->append_output(_("SDL - Simple DirectMedia Layer"),
"sdlvideosink");
m_comboVideoOutput->append_output(_("GConf"), "gconfvideosink");
#ifdef USE_OSX
m_comboVideoOutput->append_output(_("OSX"), "osxvideosink");
m_comboVideoOutput->append_output(_("OSX"), "osxvideosink");
#endif
}
m_comboVideoOutput->append_output(_("OpenGL"), "glimagesink");

Glib::ustring audiosink = cfg::get_string("video-player", "audio-sink");
Glib::ustring videosink = cfg::get_string("video-player", "video-sink");
Expand Down
4 changes: 2 additions & 2 deletions share/ui/subtitleeditor.ui
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
Expand Down Expand Up @@ -237,7 +237,7 @@
</object>
<packing>
<property name="resize">False</property>
<property name="shrink">True</property>
<property name="shrink">False</property>
</packing>
</child>
<child>
Expand Down
12 changes: 12 additions & 0 deletions src/gui/application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
#include <config.h>
#include <gtkmm/accelmap.h>
#include <algorithm>

#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif

#include "application.h"
#include "documents.h"
#include "encodings.h"
Expand Down Expand Up @@ -147,6 +152,13 @@ void Application::load_config() {
cfg::set_string("encodings", "encodings", "ISO-8859-15;UTF-8");
cfg::set_boolean("encodings", "used-auto-detected", true);
}

#ifdef GDK_WINDOWING_WAYLAND
// default to OpenGL video output on Wayland
if (GDK_IS_WAYLAND_DISPLAY(get_display()->gobj())) {
cfg::set_string("video-player", "video-sink", "glimagesink");
}
#endif
}

bool Application::on_delete_event(GdkEventAny *ev) {
Expand Down
157 changes: 127 additions & 30 deletions src/vp/gstplayer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,14 @@

#ifdef GDK_WINDOWING_X11
#include <gdk/gdkx.h>
#elif defined(GDK_WINDOWING_WIN32)
#endif
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#if defined(GDK_WINDOWING_WIN32)
#include <gdk/gdkwin32.h>
#elif defined(GDK_WINDOWING_QUARTZ)
#endif
#if defined(GDK_WINDOWING_QUARTZ)
// #include <gdk/gdkquartz.h>
#endif

Expand Down Expand Up @@ -294,6 +299,18 @@ void GstPlayer::on_realize() {
se_dbg_msg(SE_DBG_VIDEO_PLAYER, "try to realize... ok");
}

void GstPlayer::on_map() {
Gtk::DrawingArea::on_map();

set_render_rectangle();
}

void GstPlayer::on_unmap() {
Gtk::DrawingArea::on_unmap();

set_render_rectangle(false);
}

// Create a gstreamer pipeline (Gst::PlayBin2), initialize the
// audio and video sink with the configuration.
// Connect the bug message to the player.
Expand Down Expand Up @@ -527,26 +544,52 @@ void GstPlayer::on_bus_message_sync(const Glib::RefPtr<Gst::Message> &msg) {
GST_MESSAGE_TYPE_NAME(msg->gobj()),
GST_OBJECT_NAME(GST_MESSAGE_SRC(msg->gobj())));

// Ignore anything but 'prepare-window-handle' element messages
if (!gst_is_video_overlay_prepare_window_handle_message(
GST_MESSAGE(msg->gobj())))
return;
if (msg->get_message_type() == Gst::MESSAGE_NEED_CONTEXT) {
#ifdef GDK_WINDOWING_WAYLAND
auto msgNeedContext = Glib::RefPtr<Gst::MessageNeedContext>::cast_static(msg);

GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg->gobj()));
gst_video_overlay_set_window_handle(overlay, m_xWindowId);
Glib::ustring context_type;

// FIXME: open bug on gstreamermm 1.0
// Get the gstreamer element source
// Glib::RefPtr<Gst::Element> el_src =
// Glib::RefPtr<Gst::Element>::cast_static(msg->get_source());
// Has an XOverlay
// Glib::RefPtr< Gst::VideoOverlay > xoverlay =
// Glib::RefPtr<Gst::VideoOverlay>::cast_dynamic(el_src);
// xoverlay->set_window_handle(m_xWindowId);
// FIXME: https://gitlab.gnome.org/GNOME/gstreamermm/merge_requests/3
// msgNeedContext->parse(context_type);
const gchar *context_type_c = nullptr;
gst_message_parse_context_type (msg->gobj(), &context_type_c);
context_type = context_type_c;

// We don't need to keep sync message
Glib::RefPtr<Gst::Bus> bus = m_pipeline->get_bus();
bus->disable_sync_message_emission();
if (context_type == "GstWaylandDisplayHandleContextType") {
struct wl_display *wayland_display =
gdk_wayland_display_get_wl_display (get_display()->gobj());
if (wayland_display) {
auto context = Gst::Context::create(context_type, TRUE);

GstStructure *s = gst_context_writable_structure (context->gobj());
gst_structure_set (s, "display", G_TYPE_POINTER, wayland_display, NULL);

Glib::RefPtr<Gst::Element>::cast_static(msg->get_source())->set_context(context);
}
}
#endif
} else if (gst_is_video_overlay_prepare_window_handle_message(msg->gobj())) {
m_xoverlay = Glib::RefPtr<Gst::Element>::cast_dynamic(msg->get_source());
if (m_xoverlay) {
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_xoverlay->gobj()),
m_xWindowId);

set_render_rectangle();
}

// FIXME: open bug on gstreamermm 1.0
// Get the gstreamer element source
// Glib::RefPtr<Gst::Element> el_src =
// Glib::RefPtr<Gst::Element>::cast_static(msg->get_source());
// Has an XOverlay
// Glib::RefPtr< Gst::VideoOverlay > xoverlay =
// Glib::RefPtr<Gst::VideoOverlay>::cast_dynamic(el_src);
// xoverlay->set_window_handle(m_xWindowId);

// We don't need to keep sync message
m_pipeline->get_bus()->disable_sync_message_emission();
}
}

// Dispatch the gstreamer message.
Expand Down Expand Up @@ -735,23 +778,39 @@ void GstPlayer::on_config_video_player_changed(const Glib::ustring &key,
}
}

// Return the xwindow ID. (Support X11, WIN32 and QUARTZ)
// Return the xwindow ID. (Support X11, Wayland, WIN32 and QUARTZ)
// Do not call this function in a gstreamer thread, this cause crash/segfault.
// Caused by the merge of the Client-Side Windows in GTK+.
gulong GstPlayer::get_xwindow_id() {
se_dbg(SE_DBG_VIDEO_PLAYER);

gulong xWindowId = 0;
auto gdkWindow = get_window()->gobj();

#ifdef GDK_WINDOWING_X11
const gulong xWindowId = GDK_WINDOW_XID(get_window()->gobj());
#elif defined(GDK_WINDOWING_WIN32)
const gulong xWindowId = gdk_win32_drawable_get_handle(get_window()->gobj());
#elif defined(GDK_WINDOWING_QUARTZ)
// const gulong xWindowId =
// gdk_quartz_window_get_nswindow(get_window()->gobj());
const gulong xWindowId =
0; // gdk_quartz_window_get_nsview(get_window()->gobj());
#else
#error unimplemented GTK backend
if (GDK_IS_X11_WINDOW(gdkWindow)) {
xWindowId = GDK_WINDOW_XID(gdkWindow);
}
else
#endif
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW(gdkWindow)) {
xWindowId = (gulong)gdk_wayland_window_get_wl_surface(gdkWindow);
}
else
#endif
#ifdef GDK_WINDOWING_WIN32
if (GDK_IS_WIN32_WINDOW(gdkWindow)) {
xWindowId = gdk_win32_drawable_get_handle(get_window()->gobj());
}
else
#endif
#ifdef GDK_WINDOWING_QUARTZ
if (GDK_IS_QUARTZ_WINDOW(gdkWindow)) {
xWindowId = 0;
// gdk_quartz_window_get_nswindow(get_window()->gobj());
// gdk_quartz_window_get_nsview(get_window()->gobj());
}
#endif

se_dbg_msg(SE_DBG_VIDEO_PLAYER, "xWindowId=%d", xWindowId);
Expand Down Expand Up @@ -884,3 +943,41 @@ guint GstPlayer::get_text_valignment_based_on_config() {
}
return alignment;
}

void GstPlayer::on_hierarchy_changed(Widget* previous_toplevel) {
if (!previous_toplevel) {
get_toplevel()->signal_configure_event().connect(
sigc::mem_fun(*this, &GstPlayer::on_configure_event), false);
}
}

bool GstPlayer::on_configure_event(GdkEventConfigure*) {
set_render_rectangle();
return false;
}

void GstPlayer::set_render_rectangle(bool is_mapped) {
#ifdef GDK_WINDOWING_WAYLAND
if (!m_xoverlay) {
return;
}

auto gdkWindow = get_window();

if (GDK_IS_WAYLAND_WINDOW(gdkWindow->gobj())) {
int x, y, width, height;

if (is_mapped) {
width = gdkWindow->get_width();
height = gdkWindow->get_height();
} else {
width = height = 1;
}

translate_coordinates(*get_toplevel(), 0, 0, x, y);
gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_xoverlay->gobj()),
x, y, width, height);
gst_video_overlay_expose(GST_VIDEO_OVERLAY(m_xoverlay->gobj()));
}
#endif
}
17 changes: 16 additions & 1 deletion src/vp/gstplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ class GstPlayer : public Gtk::DrawingArea, public Player {
// Realize the widget and get the xWindowId.
void on_realize();

// Show the video overlay.
void on_map();

// Hide the video overlay.
void on_unmap();

// Connect to toplevel configure events.
void on_hierarchy_changed(Widget* previous_toplevel);

// Update render rectangle of GstVideoOverlay.
bool on_configure_event(GdkEventConfigure* configure_event);

// Create a gstreamer pipeline (Gst::PlayBin2), initialize the
// audio and video sink with the configuration.
// Connect the bug message to the player.
Expand Down Expand Up @@ -175,6 +187,9 @@ class GstPlayer : public Gtk::DrawingArea, public Player {
// Set up the duration value of the stream if need.
bool update_pipeline_duration();

// Update render rectangle of GstVideoOverlay.
void set_render_rectangle(bool is_mapped = true);

// Return the number of audio track.
gint get_n_audio();

Expand All @@ -192,7 +207,7 @@ class GstPlayer : public Gtk::DrawingArea, public Player {
guint m_watch_id;
// Gstreamer Elements
Glib::RefPtr<Gst::PlayBin> m_pipeline;
Glib::RefPtr<Gst::VideoOverlay> m_xoverlay;
Glib::RefPtr<Gst::Element> m_xoverlay;
Glib::RefPtr<Gst::TextOverlay> m_textoverlay;

bool m_pipeline_async_done;
Expand Down