[vlc-devel] [PATCH 5/7] qt: add a model to select where video should be rendered

Pierre Lamot pierre at videolabs.io
Fri Aug 14 18:49:03 CEST 2020


  This allows to select where the video should be rendered according to the
  capabilities of the compositor.
---
 modules/gui/qt/Makefile.am                    |   3 +
 modules/gui/qt/maininterface/mainui.cpp       |   2 +
 .../qt/util/video_surface_target_model.cpp    | 229 ++++++++++++++++++
 .../qt/util/video_surface_target_model.hpp    |  63 +++++
 4 files changed, 297 insertions(+)
 create mode 100644 modules/gui/qt/util/video_surface_target_model.cpp
 create mode 100644 modules/gui/qt/util/video_surface_target_model.hpp

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index dbb43476b8..04958cadd6 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -213,6 +213,8 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/util/varcommon_p.hpp \
 	gui/qt/util/varchoicemodel.cpp  gui/qt/util/varchoicemodel.hpp \
 	gui/qt/util/variables.cpp gui/qt/util/variables.hpp \
+	gui/qt/util/video_surface_target_model.cpp \
+	gui/qt/util/video_surface_target_model.hpp \
 	gui/qt/util/vlctick.cpp \
 	gui/qt/util/vlctick.hpp \
 	gui/qt/widgets/native/animators.cpp \
@@ -342,6 +344,7 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/util/validators.moc.cpp \
 	gui/qt/util/varchoicemodel.moc.cpp \
 	gui/qt/util/variables.moc.cpp \
+	gui/qt/util/video_surface_target_model.moc.cpp \
 	gui/qt/util/vlctick.moc.cpp \
 	gui/qt/widgets/native/animators.moc.cpp \
 	gui/qt/widgets/native/customwidgets.moc.cpp \
diff --git a/modules/gui/qt/maininterface/mainui.cpp b/modules/gui/qt/maininterface/mainui.cpp
index f371e4321e..88ed793505 100644
--- a/modules/gui/qt/maininterface/mainui.cpp
+++ b/modules/gui/qt/maininterface/mainui.cpp
@@ -25,6 +25,7 @@
 #include "util/recent_media_model.hpp"
 #include "util/settings.hpp"
 #include "util/navigation_history.hpp"
+#include "util/video_surface_target_model.hpp"
 
 #include "dialogs/help/aboutmodel.hpp"
 #include "dialogs/dialogs_provider.hpp"
@@ -196,6 +197,7 @@ void MainUI::registerQMLTypes()
     qmlRegisterUncreatableType<ProgramListModel>("org.videolan.vlc", 0, 1, "ProgramListModel", "available programs of a media" );
     qmlRegisterUncreatableType<VLCVarChoiceModel>("org.videolan.vlc", 0, 1, "VLCVarChoiceModel", "generic variable with choice model" );
     qmlRegisterUncreatableType<PlayerController>("org.videolan.vlc", 0, 1, "PlayerController", "player controller" );
+    qmlRegisterType<VideoSurfaceTargetModel>( "org.videolan.vlc", 0, 1, "VideoSurfaceTargetModel" );
 
     qRegisterMetaType<PlaylistPtr>();
     qRegisterMetaType<PlaylistItem>();
diff --git a/modules/gui/qt/util/video_surface_target_model.cpp b/modules/gui/qt/util/video_surface_target_model.cpp
new file mode 100644
index 0000000000..37ffa97892
--- /dev/null
+++ b/modules/gui/qt/util/video_surface_target_model.cpp
@@ -0,0 +1,229 @@
+/*****************************************************************************
+ * Copyright (C) 2020 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 "video_surface_target_model.hpp"
+
+#include <QGuiApplication>
+
+using namespace vlc;
+
+VideoSurfaceTargetModel::VideoSurfaceTargetModel(QObject *parent)
+        : QAbstractListModel(parent)
+{
+}
+
+QHash<int, QByteArray> VideoSurfaceTargetModel::roleNames() const
+{
+    QHash<int, QByteArray> roleNames = this->QAbstractListModel::roleNames();
+    roleNames[Qt::CheckStateRole] = "checked";
+    return roleNames;
+}
+
+void VideoSurfaceTargetModel::setCtx(QmlMainContext* ctx)
+{
+    if (m_ctx)
+    {
+        disconnect(qApp, &QGuiApplication::screenAdded,
+                   this, &VideoSurfaceTargetModel::onScreenCountChanged);
+        disconnect(qApp, &QGuiApplication::screenRemoved,
+                   this, &VideoSurfaceTargetModel::onScreenCountChanged);
+        disconnect(m_compositor, &Compositor::videoSurfaceChanged,
+                this, &VideoSurfaceTargetModel::onVideoSurfaceChanged);
+    }
+    m_ctx = ctx;
+    if (m_ctx)
+    {
+        m_compositor = ctx->getIntf()->p_sys->p_compositor;
+        m_supportedModes = m_compositor->getSupportedVideoSurfaceModes();
+        connect(m_compositor, &Compositor::videoSurfaceChanged,
+                this, &VideoSurfaceTargetModel::onVideoSurfaceChanged);
+        if (m_supportedModes & Compositor::VideoSurfaceTarget::FULLSCREEN)
+        {
+            m_screenList = QGuiApplication::screens();
+            connect(qApp, &QGuiApplication::screenAdded,
+                    this, &VideoSurfaceTargetModel::onScreenCountChanged);
+            connect(qApp, &QGuiApplication::screenRemoved,
+                    this, &VideoSurfaceTargetModel::onScreenCountChanged);
+        }
+        onScreenCountChanged();
+    }
+    emit ctxChanged();
+}
+
+int VideoSurfaceTargetModel::rowCount(const QModelIndex&) const
+{
+    int count = 0;
+    if (!m_ctx)
+        return 0;
+
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::FULLSCREEN)
+        count += m_screenList.size();
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::EMBED)
+        count += 1;
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::WINDOWED)
+        count += 1;
+    return  count;
+}
+
+QVariant VideoSurfaceTargetModel::data( const QModelIndex& index, int role ) const
+{
+    auto idx = index.row();
+
+    if (!m_ctx)
+        return {};
+
+    //first index are static entries
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::EMBED)
+    {
+        if (idx == 0)
+        {
+            switch ( role )
+            {
+                case  Qt::DisplayRole: return qtr("embed");
+                case  Qt::CheckStateRole: return m_target == index.row();
+                default: return {};
+            }
+        }
+        idx -= 1;
+    }
+
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::WINDOWED)
+    {
+        if (idx == 0)
+        {
+            switch ( role )
+            {
+                case  Qt::DisplayRole: return qtr("windowed");
+                case  Qt::CheckStateRole: return m_target == index.row();
+                default: return {};
+            }
+        }
+        idx -= 1;
+    }
+
+    if ( idx < 0 || idx >= m_screenList.size() )
+        return {};
+
+    const QScreen* screen = m_screenList[idx];
+    switch ( role )
+    {
+        case  Qt::DisplayRole: return screen->name();
+        case  Qt::CheckStateRole: return m_target == index.row();
+        default: return {};
+    }
+}
+
+
+bool VideoSurfaceTargetModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+    if (!m_ctx)
+        return false;
+
+    int row = index.row();
+    if (role != Qt::CheckStateRole)
+        return false;
+
+    //only update the variable when we select an entry
+    if (!value.toBool())
+        return false;
+
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::EMBED)
+    {
+        if (row == 0)
+        {
+            m_compositor->setVideoSurface(Compositor::VideoSurfaceTarget::EMBED);
+            return true;
+        }
+        row -= 1;
+    }
+
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::WINDOWED)
+    {
+        if (row == 0)
+        {
+            m_compositor->setVideoSurface(Compositor::VideoSurfaceTarget::WINDOWED);
+            return true;
+        }
+        row -= 1;
+    }
+
+    if (row >= 0 && row < m_screenList.size())
+    {
+        QScreen* screen = m_screenList[row];
+        m_compositor->setVideoSurface(Compositor::VideoSurfaceTarget::FULLSCREEN, QVariant(screen->name()));
+        return true;
+    }
+    return false;
+}
+
+void VideoSurfaceTargetModel::onScreenCountChanged()
+{
+    beginResetModel();
+    m_screenList = QGuiApplication::screens();
+    endResetModel();
+}
+
+void VideoSurfaceTargetModel::onVideoSurfaceChanged(Compositor::VideoSurfaceTarget target, QVariant param)
+{
+    int idx = 0;
+    bool found = false;
+    if (m_supportedModes & Compositor::VideoSurfaceTarget::EMBED)
+    {
+        if (target == Compositor::VideoSurfaceTarget::EMBED)
+            found = true;
+        else
+            idx += 1;
+    }
+
+    if (!found && (m_supportedModes & Compositor::VideoSurfaceTarget::WINDOWED))
+    {
+        if (target == Compositor::VideoSurfaceTarget::WINDOWED)
+            found = true;
+        else
+            idx += 1;
+    }
+
+    if (!found && (m_supportedModes & Compositor::VideoSurfaceTarget::FULLSCREEN))
+    {
+        if (target == Compositor::VideoSurfaceTarget::FULLSCREEN)
+        {
+            QString screenName = param.toString();
+            for (auto screen : m_screenList)
+            {
+                if (screen->name() == screenName)
+                {
+                    found = true;
+                    break;
+                }
+                idx++;
+            }
+        }
+    }
+    int oldTarget = m_target;
+    if (found)
+        m_target = idx;
+    else
+        m_target = -1;
+
+    if (oldTarget != -1)
+        emit dataChanged(index(oldTarget),index(oldTarget), {Qt::CheckStateRole});
+    if (m_target != -1)
+        emit dataChanged(index(m_target),index(m_target), {Qt::CheckStateRole});
+}
+
+
diff --git a/modules/gui/qt/util/video_surface_target_model.hpp b/modules/gui/qt/util/video_surface_target_model.hpp
new file mode 100644
index 0000000000..d7f8e6b73f
--- /dev/null
+++ b/modules/gui/qt/util/video_surface_target_model.hpp
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * Copyright (C) 2020 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 VIDEOSURFACETARGETMODEL_HPP
+#define VIDEOSURFACETARGETMODEL_HPP
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "qt.hpp"
+#include <QAbstractListModel>
+#include <QScreen>
+#include "maininterface/compositor.hpp"
+#include "qml_main_context.hpp"
+
+class VideoSurfaceTargetModel : public QAbstractListModel
+{
+    Q_OBJECT
+
+    Q_PROPERTY(QmlMainContext* ctx READ getCtx WRITE setCtx NOTIFY ctxChanged)
+public:
+    explicit VideoSurfaceTargetModel(QObject *parent = nullptr);
+
+    int rowCount(QModelIndex const &parent = {}) const  override;
+    QVariant data(QModelIndex const &index, const int role = Qt::DisplayRole) const  override;
+    bool setData(const QModelIndex &index, const QVariant &value, int role) override;
+    QHash<int, QByteArray> roleNames() const override;
+
+    void setCtx(QmlMainContext* ctx);
+    inline QmlMainContext* getCtx() const { return m_ctx; }
+
+signals:
+    void ctxChanged();
+
+private slots:
+    void onScreenCountChanged();
+    void onVideoSurfaceChanged(vlc::Compositor::VideoSurfaceTarget target, QVariant param);
+
+private:
+    QmlMainContext* m_ctx = nullptr;
+    vlc::Compositor* m_compositor = nullptr;
+    vlc::Compositor::VideoSurfaceTarget m_supportedModes = vlc::Compositor::UNDEF;
+    QList<QScreen *> m_screenList;
+    int m_target = -1; //the current target
+};
+
+#endif // VIDEOSURFACETARGETMODEL_HPP
-- 
2.25.1



More information about the vlc-devel mailing list