[vlc-devel] [RFC 48/82] qt: add wayland video renderer

Pierre Lamot pierre at videolabs.io
Fri Feb 1 14:01:52 CET 2019


From: Alexandre Janniaux <alexandre.janniaux at gmail.com>

---
 modules/gui/qt/Makefile.am                    |   9 +
 .../video_renderer/videorendererwayland.cpp   | 154 ++++++++++++++++++
 .../video_renderer/videorendererwayland.hpp   |  63 +++++++
 3 files changed, 226 insertions(+)
 create mode 100644 modules/gui/qt/components/video_renderer/videorendererwayland.cpp
 create mode 100644 modules/gui/qt/components/video_renderer/videorendererwayland.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 7d0132c6a1..e9cd3e61d4 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -166,6 +166,11 @@ if HAVE_WIN32
 libqt_plugin_la_SOURCES += \
 	gui/qt/main_interface_win32.cpp gui/qt/main_interface_win32.hpp
 endif
+if HAVE_WAYLAND
+libqt_plugin_la_SOURCES += \
+	gui/qt/components/video_renderer/videorendererwayland.hpp \
+	gui/qt/components/video_renderer/videorendererwayland.cpp
+endif
 
 # Meta-object compilation
 
@@ -260,6 +265,10 @@ if HAVE_WIN32
 nodist_libqt_plugin_la_SOURCES += gui/qt/main_interface_win32.moc.cpp
 endif
 
+if HAVE_WAYLAND
+nodist_libqt_plugin_la_SOURCES += gui/qt/components/video_renderer/videorendererwayland.moc.cpp
+endif
+
 nodist_libqt_plugin_la_SOURCES += \
 	gui/qt/ui/equalizer.h \
 	gui/qt/ui/video_effects.h \
diff --git a/modules/gui/qt/components/video_renderer/videorendererwayland.cpp b/modules/gui/qt/components/video_renderer/videorendererwayland.cpp
new file mode 100644
index 0000000000..120bb9a24c
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorendererwayland.cpp
@@ -0,0 +1,154 @@
+#include "videorendererwayland.hpp"
+#include <QtQuick/QSGImageNode>
+#include <QtQuick/QSGRectangleNode>
+#include <QtQuick/QQuickWindow>
+#include <vlc_vout_window.h>
+#include "main_interface.hpp"
+
+#include QPNI_HEADER
+#include <wayland-client.h>
+#include <wayland-client-protocol.h>
+
+void VideoRendererWayland::registry_global( void *data, wl_registry *registry,
+                                       uint32_t name, const char *intf,
+                                       uint32_t version )
+{
+    VideoRendererWayland *renderer = static_cast<VideoRendererWayland*>( data );
+
+    if( !strcmp(intf, "wl_compositor") )
+        renderer->m_compositor = static_cast<wl_compositor*>(
+                                 wl_registry_bind( registry, name,
+                                                   &wl_compositor_interface,
+                                                   version ));
+
+    else
+    if( !strcmp(intf, "wl_subcompositor") )
+        renderer->m_subcompositor = static_cast<wl_subcompositor*>(
+                                    wl_registry_bind( registry, name,
+                                                      &wl_subcompositor_interface,
+                                                      version ));
+}
+
+void VideoRendererWayland::registry_global_remove( void *, wl_registry *, uint32_t )
+{
+    // nothing to do
+}
+
+VideoRendererWayland::VideoRendererWayland( MainInterface* p_mi, QObject* parent )
+    : VideoRenderer( parent )
+    , m_mainInterface( p_mi )
+{
+    assert( m_mainInterface );
+    m_surfaceProvider = new VideoSurfaceWayland( this, this );
+}
+
+VideoRendererWayland::~VideoRendererWayland()
+{
+    if( m_subsurface )
+        wl_subsurface_destroy( m_subsurface );
+    if( m_surface )
+        wl_surface_destroy( m_surface );
+    if( m_compositor )
+        wl_compositor_destroy( m_compositor );
+    if( m_subcompositor )
+        wl_subcompositor_destroy( m_subcompositor );
+}
+
+void VideoRendererWayland::enableVideo(unsigned width, unsigned height, bool fullscreen)
+{
+    VideoRenderer::enableVideo(width, height, fullscreen);
+    if (!m_hasVideo) //no window out has been set
+        return;
+
+    m_voutWindow->type = VOUT_WINDOW_TYPE_WAYLAND;
+
+    QPlatformNativeInterface *qni = qApp->platformNativeInterface();
+
+    m_voutWindow->display.wl = static_cast<wl_display *>(
+         qni->nativeResourceForIntegration(QByteArrayLiteral("wl_display")));
+
+    const wl_registry_listener registry_cbs =
+    {
+        registry_global,
+        registry_global_remove,
+    };
+
+    wl_registry *registry = wl_display_get_registry( m_voutWindow->display.wl );
+    wl_registry_add_listener( registry, &registry_cbs, this );
+    wl_display_roundtrip( m_voutWindow->display.wl );
+    wl_registry_destroy( registry );
+
+    if( !m_compositor || !m_subcompositor )
+        return; // TODO: what to do
+
+    QWindow *root_window = m_mainInterface->window()->windowHandle();
+    wl_surface *root_surface = static_cast<wl_surface *>(
+        qni->nativeResourceForWindow( QByteArrayLiteral("surface"),
+                                      root_window ));
+
+    m_surface =
+    m_voutWindow->handle.wl = wl_compositor_create_surface( m_compositor );
+    m_subsurface = wl_subcompositor_get_subsurface( m_subcompositor,
+                                                    m_voutWindow->handle.wl,
+                                                    root_surface );
+
+    wl_subsurface_place_below( m_subsurface, root_surface );
+    wl_subsurface_set_desync( m_subsurface );
+
+    /* HACK: disable event input on surface, so that Qt don't try
+     * to cast it's userdata */
+    wl_region *region = wl_compositor_create_region( m_compositor );
+    wl_region_add( region, 0, 0, 0, 0 );
+    wl_surface_set_input_region( m_voutWindow->handle.wl, region );
+    wl_region_destroy( region );
+}
+
+
+void VideoRendererWayland::disableVideo()
+{
+    VideoRenderer::disableVideo();
+    if( m_subsurface )
+        wl_subsurface_destroy( m_subsurface );
+    if( m_surface )
+        wl_surface_destroy( m_surface );
+    if( m_subcompositor )
+        wl_subcompositor_destroy( m_subcompositor );
+    if( m_compositor )
+        wl_compositor_destroy( m_compositor );
+    m_subsurface = nullptr; m_surface = nullptr;
+    m_compositor = nullptr; m_subcompositor = nullptr;
+}
+
+VideoSurfaceProvider *VideoRendererWayland::getVideoSurfaceProvider()
+{
+    return m_surfaceProvider;
+}
+
+VideoSurfaceWayland::VideoSurfaceWayland(VideoRendererWayland* renderer, QObject* parent)
+    : VideoSurfaceProvider( parent )
+    , m_renderer(renderer)
+{
+    connect(this, &VideoSurfaceWayland::mouseMoved, m_renderer, &VideoRenderer::onMouseMoved, Qt::QueuedConnection);
+    connect(this, &VideoSurfaceWayland::mousePressed, m_renderer, &VideoRenderer::onMousePressed, Qt::QueuedConnection);
+    connect(this, &VideoSurfaceWayland::mouseDblClicked, m_renderer, &VideoRenderer::onMouseDoubleClick, Qt::QueuedConnection);
+    connect(this, &VideoSurfaceWayland::mouseReleased, m_renderer, &VideoRenderer::onMouseReleased, Qt::QueuedConnection);
+
+    connect(this, &VideoSurfaceWayland::surfaceSizeChanged, m_renderer, &VideoRenderer::onSurfaceSizeChanged);
+
+    connect(m_renderer, &VideoRendererWayland::updated, this, &VideoSurfaceWayland::update, Qt::QueuedConnection);
+}
+
+QSGNode* VideoSurfaceWayland::updatePaintNode(QQuickItem* item, QSGNode* oldNode, QQuickItem::UpdatePaintNodeData*)
+{
+    QSGRectangleNode* node = static_cast<QSGRectangleNode*>(oldNode);
+
+    if (!node)
+    {
+        node = item->window()->createRectangleNode();
+        node->setColor(Qt::transparent);
+    }
+    node->setRect(item->boundingRect());
+
+    return node;
+}
+
diff --git a/modules/gui/qt/components/video_renderer/videorendererwayland.hpp b/modules/gui/qt/components/video_renderer/videorendererwayland.hpp
new file mode 100644
index 0000000000..c3c3462368
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorendererwayland.hpp
@@ -0,0 +1,63 @@
+#ifndef VLC_QT_VIDEORENDERERWL_HPP
+#define VLC_QT_VIDEORENDERERWL_HPP
+
+#include <inttypes.h>
+#include <QtQuick/QQuickItem>
+#include <QMutex>
+#include <QtQuick/QSGRectangleNode>
+#include <components/qml_main_context.hpp>
+#include "qt.hpp"
+
+#include "videorenderer.hpp"
+
+class MainInterface;
+class VideoSurfaceWayland;
+
+struct wl_compositor;
+struct wl_subcompositor;
+struct wl_subsurface;
+struct wl_registry;
+
+class VideoRendererWayland: public VideoRenderer
+{
+    Q_OBJECT
+public:
+    VideoRendererWayland(MainInterface* p_mi,  QObject *parent = nullptr);
+    ~VideoRendererWayland() override;
+
+    void enableVideo(unsigned int width, unsigned int height, bool fullscreen);
+    void disableVideo();
+
+    VideoSurfaceProvider *getVideoSurfaceProvider() override;
+
+signals:
+    void updated();
+
+private:
+    /* wayland registry callbacks */
+    static void registry_global( void *, wl_registry *, uint32_t,
+                                 const char *, uint32_t );
+    static void registry_global_remove( void *, wl_registry *, uint32_t );
+
+    MainInterface *m_mainInterface;
+    VideoSurfaceWayland *m_surfaceProvider = nullptr;
+    wl_compositor *m_compositor = nullptr;
+    wl_subcompositor *m_subcompositor = nullptr;
+    wl_subsurface *m_subsurface = nullptr;
+    wl_surface *m_surface = nullptr;
+};
+
+class VideoSurfaceWayland : public VideoSurfaceProvider
+{
+    Q_OBJECT
+public:
+    VideoSurfaceWayland(VideoRendererWayland* renderer, QObject* parent = nullptr);
+
+private:
+    QSGNode *updatePaintNode(QQuickItem* item, QSGNode *, QQuickItem::UpdatePaintNodeData *) override;
+
+private:
+    VideoRendererWayland* m_renderer = nullptr;
+};
+
+#endif // VLC_QT_VIDEORENDERERWL_HPP
-- 
2.19.1



More information about the vlc-devel mailing list