[vlc-devel] [RFC 44/82] qt: provide base implementation video sink to render video output within the interface

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


  VideoSurface provide a QQuickItem which can be embed within a QML scene to
  represent the video node.

  VideoSurfaceProvider is the actual implementation of the VideoSurface which will
  be selected at runtime

  VideoRenderer implement a video sink which will be in charge of rendering the video
---
 modules/gui/qt/Makefile.am                    |   6 +
 .../video_renderer/videorenderer.cpp          |  63 +++++++
 .../video_renderer/videorenderer.hpp          |  37 ++++
 .../video_renderer/videosurface.cpp           | 170 ++++++++++++++++++
 .../video_renderer/videosurface.hpp           | 102 +++++++++++
 5 files changed, 378 insertions(+)
 create mode 100644 modules/gui/qt/components/video_renderer/videorenderer.cpp
 create mode 100644 modules/gui/qt/components/video_renderer/videorenderer.hpp
 create mode 100644 modules/gui/qt/components/video_renderer/videosurface.cpp
 create mode 100644 modules/gui/qt/components/video_renderer/videosurface.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index d48aa0c1e2..c061c8a2bd 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -98,6 +98,10 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/components/controller.cpp gui/qt/components/controller.hpp \
 	gui/qt/components/controller_widget.cpp \
 	gui/qt/components/controller_widget.hpp \
+	gui/qt/components/video_renderer/videosurface.cpp \
+	gui/qt/components/video_renderer/videosurface.hpp \
+	gui/qt/components/video_renderer/videorenderer.cpp \
+	gui/qt/components/video_renderer/videorenderer.hpp \
 	gui/qt/components/custom_menus.cpp \
 	gui/qt/components/custom_menus.hpp \
 	gui/qt/components/epg/EPGChannels.cpp \
@@ -216,6 +220,8 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/components/controller.moc.cpp \
 	gui/qt/components/controller_widget.moc.cpp \
 	gui/qt/components/custom_menus.moc.cpp \
+	gui/qt/components/video_renderer/videosurface.moc.cpp \
+	gui/qt/components/video_renderer/videorenderer.moc.cpp \
 	gui/qt/components/epg/EPGChannels.moc.cpp \
 	gui/qt/components/epg/EPGProgram.moc.cpp \
 	gui/qt/components/epg/EPGRuler.moc.cpp \
diff --git a/modules/gui/qt/components/video_renderer/videorenderer.cpp b/modules/gui/qt/components/video_renderer/videorenderer.cpp
new file mode 100644
index 0000000000..09150f372d
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorenderer.cpp
@@ -0,0 +1,63 @@
+#include "videorenderer.hpp"
+
+VideoRenderer::VideoRenderer(QObject* parent)
+    : QObject(parent)
+{
+}
+
+void VideoRenderer::setupVoutWindow(vout_window_t* window)
+{
+    QMutexLocker lock(&m_voutlock);
+    m_voutWindow = window;
+    m_hasVideo = false;
+}
+
+void VideoRenderer::enableVideo(unsigned /*width*/, unsigned /*height*/, bool /*fullscreen*/)
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_voutWindow)
+        m_hasVideo = true;
+}
+
+void VideoRenderer::disableVideo()
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_voutWindow)
+        m_hasVideo = false;
+}
+
+void VideoRenderer::onMousePressed(int vlcButton)
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_hasVideo)
+        vout_window_ReportMousePressed(m_voutWindow, vlcButton);
+}
+
+void VideoRenderer::onMouseReleased(int vlcButton)
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_hasVideo)
+        vout_window_ReportMouseReleased(m_voutWindow, vlcButton);
+}
+
+void VideoRenderer::onMouseDoubleClick(int vlcButton)
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_hasVideo)
+        vout_window_ReportMouseDoubleClick(m_voutWindow, vlcButton);
+}
+
+void VideoRenderer::onMouseMoved(float x, float y)
+{
+    QMutexLocker lock(&m_voutlock);
+    if (m_hasVideo)
+        vout_window_ReportMouseMoved(m_voutWindow, x, y);
+}
+
+void VideoRenderer::onSurfaceSizeChanged(QSizeF size)
+{
+
+    QMutexLocker lock(&m_voutlock);
+    if (m_hasVideo)
+        vout_window_ReportSize(m_voutWindow, size.width(), size.height());
+}
diff --git a/modules/gui/qt/components/video_renderer/videorenderer.hpp b/modules/gui/qt/components/video_renderer/videorenderer.hpp
new file mode 100644
index 0000000000..98e3ea26c2
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorenderer.hpp
@@ -0,0 +1,37 @@
+#ifndef VIDEORENDERER_HPP
+#define VIDEORENDERER_HPP
+
+#include <QObject>
+#include <QMutex>
+#include "qt.hpp"
+#include "vlc_vout_window.h"
+#include "videosurface.hpp"
+
+class VideoRenderer : public QObject
+{
+    Q_OBJECT
+public:
+    VideoRenderer(QObject* parent = nullptr);
+    virtual ~VideoRenderer() {}
+
+    virtual void setupVoutWindow(vout_window_t* window);
+    virtual void enableVideo(unsigned width, unsigned height, bool fullscreen);
+    virtual void disableVideo();
+
+    virtual VideoSurfaceProvider* getVideoSurfaceProvider() = 0;
+
+public slots:
+    void onMousePressed( int vlcButton );
+    void onMouseReleased( int vlcButton );
+    void onMouseDoubleClick( int vlcButton );
+    void onMouseMoved( float x, float y );
+    void onSurfaceSizeChanged(QSizeF size);
+
+protected:
+    QMutex m_voutlock;
+    vout_window_t* m_voutWindow = nullptr;
+    bool m_hasVideo = false;
+
+};
+
+#endif // VIDEORENDERER_HPP
diff --git a/modules/gui/qt/components/video_renderer/videosurface.cpp b/modules/gui/qt/components/video_renderer/videosurface.cpp
new file mode 100644
index 0000000000..39b453c3c1
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videosurface.cpp
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include "videosurface.hpp"
+#include "main_interface.hpp"
+
+
+VideoSurfaceProvider::VideoSurfaceProvider(QObject* parent)
+    : QObject(parent)
+{
+}
+
+VideoSurface::VideoSurface(QQuickItem* parent)
+    : QQuickItem(parent)
+{
+    setAcceptHoverEvents(true);
+    setAcceptedMouseButtons(Qt::AllButtons);
+    setFlag(ItemAcceptsInputMethod, true);
+    setFlag(ItemHasContents, true);
+
+    connect(this, &QQuickItem::widthChanged, this, &VideoSurface::onSurfaceSizeChanged);
+    connect(this, &QQuickItem::heightChanged, this, &VideoSurface::onSurfaceSizeChanged);
+}
+
+QmlMainContext*VideoSurface::getCtx()
+{
+    return m_mainCtx;
+}
+
+void VideoSurface::setCtx(QmlMainContext* mainctx)
+{
+    m_mainCtx = mainctx;
+    emit ctxChanged(mainctx);
+}
+
+QSize VideoSurface::getSourceSize() const
+{
+    return m_sourceSize;
+}
+
+int VideoSurface::qtMouseButton2VLC( Qt::MouseButton qtButton )
+{
+    switch( qtButton )
+    {
+        case Qt::LeftButton:
+            return 0;
+        case Qt::RightButton:
+            return 2;
+        case Qt::MiddleButton:
+            return 1;
+        default:
+            return -1;
+    }
+}
+
+void VideoSurface::mousePressEvent(QMouseEvent* event)
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        emit mousePressed(vlc_button);
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void VideoSurface::mouseReleaseEvent(QMouseEvent* event)
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        emit mouseReleased(vlc_button);
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+void VideoSurface::mouseMoveEvent(QMouseEvent* event)
+{
+    QPointF current_pos = event->localPos();
+    emit mouseMoved(current_pos.x() , current_pos.y());
+    event->accept();
+}
+
+void VideoSurface::hoverMoveEvent(QHoverEvent* event)
+{
+    QPointF current_pos = event->posF();
+    if (current_pos != m_oldHoverPos)
+    {
+        float scaleW = m_sourceSize.width() / width();
+        float scaleH = m_sourceSize.height() / height();
+        emit mouseMoved(current_pos.x() * scaleW, current_pos.y() * scaleH);
+        m_oldHoverPos = current_pos;
+    }
+    event->accept();
+}
+
+void VideoSurface::mouseDoubleClickEvent(QMouseEvent* event)
+{
+    int vlc_button = qtMouseButton2VLC( event->button() );
+    if( vlc_button >= 0 )
+    {
+        emit mouseDblClicked(vlc_button);
+        event->accept();
+    }
+    else
+        event->ignore();
+}
+
+Qt::CursorShape VideoSurface::getCursorShape() const
+{
+    return cursor().shape();
+}
+
+void VideoSurface::setCursorShape(Qt::CursorShape shape)
+{
+    setCursor(shape);
+}
+
+QSGNode*VideoSurface::updatePaintNode(QSGNode* node, QQuickItem::UpdatePaintNodeData* nodeData)
+{
+    if (m_provider == nullptr) {
+        if (m_mainCtx == nullptr)
+            return nullptr;
+        m_provider =  m_mainCtx->getMainInterface()->getVideoSurfaceProvider();
+        if (!m_provider)
+            return nullptr;
+
+        //forward signal to the provider
+        connect(this, &VideoSurface::mouseMoved, m_provider, &VideoSurfaceProvider::mouseMoved);
+        connect(this, &VideoSurface::mousePressed, m_provider, &VideoSurfaceProvider::mousePressed);
+        connect(this, &VideoSurface::mouseDblClicked, m_provider, &VideoSurfaceProvider::mouseDblClicked);
+        connect(this, &VideoSurface::mouseReleased, m_provider, &VideoSurfaceProvider::mouseReleased);
+
+        connect(this, &VideoSurface::surfaceSizeChanged, m_provider, &VideoSurfaceProvider::surfaceSizeChanged);
+
+        connect(m_provider, &VideoSurfaceProvider::update, this, &VideoSurface::update);
+        connect(m_provider, &VideoSurfaceProvider::sourceSizeChanged, this, &VideoSurface::onSourceSizeChanged);
+    }
+    return m_provider->updatePaintNode(this, node, nodeData);
+}
+
+void VideoSurface::onSourceSizeChanged(QSize newSize)
+{
+    if (newSize != m_sourceSize) {
+        m_sourceSize = newSize;
+        emit sourceSizeChanged(m_sourceSize);
+    }
+}
+
+void VideoSurface::onSurfaceSizeChanged()
+{
+    emit surfaceSizeChanged(size());
+}
diff --git a/modules/gui/qt/components/video_renderer/videosurface.hpp b/modules/gui/qt/components/video_renderer/videosurface.hpp
new file mode 100644
index 0000000000..41cb257a0a
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videosurface.hpp
@@ -0,0 +1,102 @@
+/*****************************************************************************
+ * Copyright (C) 2019 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#ifndef VIDEOSURFACE_HPP
+#define VIDEOSURFACE_HPP
+
+#include <QtQuick/QQuickItem>
+#include <QCursor>
+#include <components/qml_main_context.hpp>
+#include "qt.hpp"
+
+class VideoSurfaceProvider : public QObject
+{
+    Q_OBJECT
+public:
+    VideoSurfaceProvider(QObject* parent);
+    virtual ~VideoSurfaceProvider() {}
+    virtual QSGNode* updatePaintNode(QQuickItem* item, QSGNode* oldNode, QQuickItem::UpdatePaintNodeData*) = 0;
+
+signals:
+    void ctxChanged(QmlMainContext*);
+    void sourceSizeChanged(QSize);
+
+    void surfaceSizeChanged(QSizeF);
+
+    void mousePressed( int vlcButton );
+    void mouseReleased( int vlcButton );
+    void mouseDblClicked( int vlcButton );
+    void mouseMoved( float x, float y );
+
+    void update();
+};
+
+
+class VideoSurface : public QQuickItem
+{
+    Q_OBJECT
+    Q_PROPERTY(QmlMainContext* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged)
+    Q_PROPERTY(QSize sourceSize READ getSourceSize NOTIFY sourceSizeChanged)
+    Q_PROPERTY(Qt::CursorShape cursorShape READ getCursorShape WRITE setCursorShape RESET unsetCursor)
+
+public:
+    VideoSurface( QQuickItem* parent = nullptr );
+
+    QmlMainContext* getCtx();
+    void setCtx(QmlMainContext* mainctx);
+
+    QSize getSourceSize() const;
+
+protected:
+    int qtMouseButton2VLC( Qt::MouseButton qtButton );
+
+    virtual void mousePressEvent(QMouseEvent *event) override;
+    virtual void mouseReleaseEvent(QMouseEvent *event) override;
+    virtual void mouseMoveEvent(QMouseEvent *event) override;
+    virtual void hoverMoveEvent(QHoverEvent *event) override;
+    virtual void mouseDoubleClickEvent(QMouseEvent *event) override;
+
+    Qt::CursorShape getCursorShape() const;
+    void setCursorShape(Qt::CursorShape);
+
+    virtual QSGNode* updatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *) override;
+
+signals:
+    void ctxChanged(QmlMainContext*);
+    void sourceSizeChanged(QSize);
+    void surfaceSizeChanged(QSizeF);
+
+    void mousePressed( int vlcButton );
+    void mouseReleased( int vlcButton );
+    void mouseDblClicked( int vlcButton );
+    void mouseMoved( float x, float y );
+
+private slots:
+    void onSourceSizeChanged(QSize);
+    void onSurfaceSizeChanged();
+
+private:
+    QmlMainContext* m_mainCtx = nullptr;
+
+    bool m_sourceSizeChanged = false;
+    QSize m_sourceSize;
+    QPointF m_oldHoverPos;
+
+    VideoSurfaceProvider* m_provider = nullptr;
+};
+
+#endif // VIDEOSURFACE_HPP
-- 
2.19.1



More information about the vlc-devel mailing list