[vlc-devel] [RFC 46/82] qt: provide OpenGL video renderer
Pierre Lamot
pierre at videolabs.io
Fri Feb 1 14:01:50 CET 2019
---
modules/gui/qt/Makefile.am | 3 +
.../video_renderer/videorenderer.cpp | 7 +
.../video_renderer/videorenderer.hpp | 2 +-
.../video_renderer/videorenderergl.cpp | 227 ++++++++++++++++++
.../video_renderer/videorenderergl.hpp | 101 ++++++++
5 files changed, 339 insertions(+), 1 deletion(-)
create mode 100644 modules/gui/qt/components/video_renderer/videorenderergl.cpp
create mode 100644 modules/gui/qt/components/video_renderer/videorenderergl.hpp
diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 4fef55cfad..7d0132c6a1 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -104,6 +104,8 @@ libqt_plugin_la_SOURCES = \
gui/qt/components/video_renderer/videorenderer.hpp \
gui/qt/components/video_renderer/videorendererdummy.cpp \
gui/qt/components/video_renderer/videorendererdummy.hpp \
+ gui/qt/components/video_renderer/videorenderergl.cpp \
+ gui/qt/components/video_renderer/videorenderergl.hpp \
gui/qt/components/custom_menus.cpp \
gui/qt/components/custom_menus.hpp \
gui/qt/components/epg/EPGChannels.cpp \
@@ -225,6 +227,7 @@ nodist_libqt_plugin_la_SOURCES = \
gui/qt/components/video_renderer/videosurface.moc.cpp \
gui/qt/components/video_renderer/videorenderer.moc.cpp \
gui/qt/components/video_renderer/videorendererdummy.moc.cpp \
+ gui/qt/components/video_renderer/videorenderergl.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
index 09150f372d..d27987f7a9 100644
--- a/modules/gui/qt/components/video_renderer/videorenderer.cpp
+++ b/modules/gui/qt/components/video_renderer/videorenderer.cpp
@@ -5,6 +5,13 @@ VideoRenderer::VideoRenderer(QObject* parent)
{
}
+VideoRenderer::~VideoRenderer()
+{
+ QMutexLocker lock(&m_voutlock);
+ if (m_voutWindow)
+ vout_window_ReportClose(m_voutWindow);
+}
+
void VideoRenderer::setupVoutWindow(vout_window_t* window)
{
QMutexLocker lock(&m_voutlock);
diff --git a/modules/gui/qt/components/video_renderer/videorenderer.hpp b/modules/gui/qt/components/video_renderer/videorenderer.hpp
index 98e3ea26c2..d94ec5e1aa 100644
--- a/modules/gui/qt/components/video_renderer/videorenderer.hpp
+++ b/modules/gui/qt/components/video_renderer/videorenderer.hpp
@@ -12,7 +12,7 @@ class VideoRenderer : public QObject
Q_OBJECT
public:
VideoRenderer(QObject* parent = nullptr);
- virtual ~VideoRenderer() {}
+ virtual ~VideoRenderer();
virtual void setupVoutWindow(vout_window_t* window);
virtual void enableVideo(unsigned width, unsigned height, bool fullscreen);
diff --git a/modules/gui/qt/components/video_renderer/videorenderergl.cpp b/modules/gui/qt/components/video_renderer/videorenderergl.cpp
new file mode 100644
index 0000000000..7e01f8d60b
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorenderergl.cpp
@@ -0,0 +1,227 @@
+#include "videorenderergl.hpp"
+#include <QtQuick/QSGImageNode>
+#include <QtQuick/QSGRectangleNode>
+#include <QtQuick/QQuickWindow>
+#include <vlc_vout_window.h>
+#include "main_interface.hpp"
+
+VideoRendererGL::VideoRendererGL(MainInterface* p_mi, QObject* parent)
+ : VideoRenderer(parent)
+ , m_mainInterface(p_mi)
+{
+ assert(m_mainInterface);
+ m_surfaceProvider = new VideoSurfaceGL(this);
+ for (int i = 0; i < 3; i++)
+ {
+ m_fbo[i] = nullptr;
+ m_textures[i] = nullptr;
+ }
+}
+
+QSharedPointer<QSGTexture> VideoRendererGL::getDisplayTexture()
+{
+ QMutexLocker lock(&m_lock);
+ if (!m_hasTextures)
+ return nullptr;
+ if (m_updated)
+ {
+ qSwap(m_displayIdx, m_bufferIdx);
+ m_updated = false;
+ }
+ return m_textures[m_displayIdx];
+}
+
+bool VideoRendererGL::make_current_cb(void* data, bool current)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+ QMutexLocker lock(&that->m_lock);
+ if (!that->m_ctx || !that->m_surface)
+ {
+ return false;
+ }
+
+ if (current)
+ return that->m_ctx->makeCurrent(that->m_surface);
+ else
+ that->m_ctx->doneCurrent();
+ return true;
+}
+
+void*VideoRendererGL::get_proc_address_cb(void* data, const char* procName)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+ return (void*)that->m_ctx->getProcAddress(procName);
+}
+
+void VideoRendererGL::swap_cb(void* data)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+ {
+ QMutexLocker lock(&that->m_lock);
+ qSwap(that->m_renderIdx, that->m_bufferIdx);
+ that->m_updated = true;
+ that->m_hasTextures = true;
+ }
+ that->m_fbo[that->m_renderIdx]->bind();
+ emit that->updated();
+}
+
+bool VideoRendererGL::setup_cb(void* data)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+
+ QMutexLocker lock(&that->m_lock);
+ that->m_window = that->m_mainInterface->getRootQuickWindow();
+ if (! that->m_window)
+ return false;
+
+ QOpenGLContext *current = that->m_window->openglContext();
+
+ that->m_ctx = new QOpenGLContext();
+ if (!that->m_ctx)
+ {
+ that->m_window = nullptr;
+ return false;
+ }
+ QSurfaceFormat format = current->format();
+
+ that->m_ctx->setFormat(format);
+ that->m_ctx->setShareContext(current);
+ that->m_ctx->create();
+
+ that->m_surface = new QOffscreenSurface();
+ if (!that->m_surface)
+ {
+ that->m_window = nullptr;
+ delete that->m_ctx;
+ that->m_ctx = nullptr;
+ return false;
+ }
+ that->m_surface->setFormat(that->m_ctx->format());
+ that->m_surface->create();
+
+ that->m_glViewport = (GlViewportPF)that->m_ctx->getProcAddress("glViewport");
+
+ return true;
+}
+
+void VideoRendererGL::cleanup_cb(void* data)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+
+ QMutexLocker lock(&that->m_lock);
+ for (int i =0; i < 3; i++)
+ {
+ if (that->m_fbo[i])
+ {
+ delete that->m_fbo[i];
+ that->m_fbo[i] = nullptr;
+ }
+ if (that->m_textures[i])
+ {
+ that->m_textures[i] = nullptr;
+ }
+ }
+ that->m_size = QSize();
+ that->m_window = nullptr;
+ that->m_hasTextures = false;
+}
+
+void VideoRendererGL::resize_cb(void* data, unsigned width, unsigned height)
+{
+ VideoRendererGL* that = static_cast<VideoRendererGL*>(data);
+
+ QMutexLocker lock(&that->m_lock);
+ QSize newsize(width, height);
+ if (that->m_size != newsize)
+ {
+ that->m_size = newsize;
+ for (int i =0; i < 3; i++)
+ {
+ if (that->m_fbo[i])
+ delete that->m_fbo[i];
+ that->m_fbo[i] = new QOpenGLFramebufferObject(newsize);
+ that->m_textures[i] = QSharedPointer<QSGTexture>(that->m_window->createTextureFromId(that->m_fbo[i]->texture(), newsize));
+ that->m_hasTextures = false;
+ }
+ emit that->sizeChanged(newsize);
+ }
+ that->m_fbo[that->m_renderIdx]->bind();
+ //set the initial viewport
+ that->m_glViewport(0, 0, width, height);
+}
+
+void VideoRendererGL::setupVoutWindow(vout_window_t* voutWindow)
+{
+ VideoRenderer::setupVoutWindow(voutWindow);
+ var_Create( voutWindow, "vout", VLC_VAR_STRING );
+ var_Create( voutWindow, "gl", VLC_VAR_STRING );
+
+ var_SetString ( voutWindow, "vout", "gl" );
+ var_SetString ( voutWindow, "gl", "vgl");
+
+ var_Create( voutWindow, "vout-cb-opaque", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-setup", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-cleanup", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-update-output", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-swap", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-make-current", VLC_VAR_ADDRESS );
+ var_Create( voutWindow, "vout-cb-get-proc-address", VLC_VAR_ADDRESS );
+
+ var_SetAddress( voutWindow, "vout-cb-opaque", this );
+ var_SetAddress( voutWindow, "vout-cb-setup", (void*)&VideoRendererGL::setup_cb );
+ var_SetAddress( voutWindow, "vout-cb-cleanup", (void*)&VideoRendererGL::cleanup_cb );
+ var_SetAddress( voutWindow, "vout-cb-update-output", (void*)&VideoRendererGL::resize_cb );
+ var_SetAddress( voutWindow, "vout-cb-swap", (void*)&VideoRendererGL::swap_cb );
+ var_SetAddress( voutWindow, "vout-cb-make-current", (void*)&VideoRendererGL::make_current_cb );
+ var_SetAddress( voutWindow, "vout-cb-get-proc-address", (void*)&VideoRendererGL::get_proc_address_cb );
+}
+
+VideoSurfaceProvider*VideoRendererGL::getVideoSurfaceProvider()
+{
+ return m_surfaceProvider;
+}
+
+////////
+
+
+VideoSurfaceGL::VideoSurfaceGL(VideoRendererGL* renderer, QObject* parent)
+ : VideoSurfaceProvider(parent)
+ , m_renderer(renderer)
+{
+ connect(this, &VideoSurfaceGL::mouseMoved, m_renderer, &VideoRenderer::onMouseMoved);
+ connect(this, &VideoSurfaceGL::mousePressed, m_renderer, &VideoRenderer::onMousePressed);
+ connect(this, &VideoSurfaceGL::mouseDblClicked, m_renderer, &VideoRenderer::onMouseDoubleClick);
+ connect(this, &VideoSurfaceGL::mouseReleased, m_renderer, &VideoRenderer::onMouseReleased);
+
+ connect(this, &VideoSurfaceGL::surfaceSizeChanged, m_renderer, &VideoRenderer::onSurfaceSizeChanged);
+
+ connect(m_renderer, &VideoRendererGL::updated, this, &VideoSurfaceGL::update, Qt::QueuedConnection);
+ connect(m_renderer, &VideoRendererGL::sizeChanged, this, &VideoSurfaceGL::sourceSizeChanged, Qt::QueuedConnection);
+}
+
+QSGNode* VideoSurfaceGL::updatePaintNode(QQuickItem* item, QSGNode* oldNode, QQuickItem::UpdatePaintNodeData*)
+{
+ QSGSimpleTextureNode* node = static_cast<QSGSimpleTextureNode*>(oldNode);
+
+ QSharedPointer<QSGTexture> newdisplayTexture = m_renderer->getDisplayTexture();
+ if (!newdisplayTexture)
+ {
+ if (node)
+ node->setRect(item->boundingRect());
+ return node;
+ }
+ m_displayTexture = newdisplayTexture;
+
+ if (!node)
+ {
+ node = new QSGSimpleTextureNode();
+ node->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
+ }
+
+ node->setTexture(m_displayTexture.data());
+ node->setRect(item->boundingRect());
+ node->markDirty(QSGNode::DirtyMaterial);
+ return node;
+}
+
diff --git a/modules/gui/qt/components/video_renderer/videorenderergl.hpp b/modules/gui/qt/components/video_renderer/videorenderergl.hpp
new file mode 100644
index 0000000000..b7aeda3f07
--- /dev/null
+++ b/modules/gui/qt/components/video_renderer/videorenderergl.hpp
@@ -0,0 +1,101 @@
+/*****************************************************************************
+ * 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 VIDEORENDERERGL_HPP
+#define VIDEORENDERERGL_HPP
+
+#include <QtQuick/QQuickItem>
+#include <QOpenGLContext>
+#include <QOpenGLFramebufferObject>
+#include <QOffscreenSurface>
+#include <QMutex>
+#include <QtQuick/QSGSimpleTextureNode>
+#include <QtQuick/QSGRectangleNode>
+#include <components/qml_main_context.hpp>
+#include "qt.hpp"
+#include "main_interface.hpp"
+#include "videosurface.hpp"
+#include "videorenderer.hpp"
+
+class VideoSurfaceGL;
+
+class VideoRendererGL : public VideoRenderer
+{
+ Q_OBJECT
+public:
+ VideoRendererGL(MainInterface* p_mi, QObject *parent = nullptr);
+
+ QSharedPointer<QSGTexture> getDisplayTexture();
+
+ void setupVoutWindow(vout_window_t* window) override;
+
+ VideoSurfaceProvider* getVideoSurfaceProvider() override;
+
+private:
+ //openGL callbacks
+ static bool make_current_cb(void* data, bool current);
+ static void* get_proc_address_cb(void* data, const char* procName);
+ static void swap_cb(void* data);
+ static bool setup_cb(void* data);
+ static void cleanup_cb(void* data);
+ static void resize_cb(void* data, unsigned width, unsigned height);
+
+signals:
+ void updated();
+ void sizeChanged(QSize);
+
+private:
+ QMutex m_lock;
+
+ QOpenGLContext* m_ctx = nullptr;
+ QOffscreenSurface* m_surface = nullptr;
+
+ MainInterface* m_mainInterface = nullptr;
+ QQuickWindow* m_window = nullptr;
+ QSize m_size;
+
+ QSharedPointer<QSGTexture> m_textures[3] ;
+ QOpenGLFramebufferObject* m_fbo[3];
+
+ bool m_hasTextures = false;
+ bool m_updated = false;
+ int m_renderIdx = 0;
+ int m_bufferIdx = 0;
+ int m_displayIdx = 0;
+
+ VideoSurfaceGL* m_surfaceProvider = nullptr;
+
+ typedef void (*GlViewportPF)(GLint, GLint, GLsizei, GLsizei);
+ GlViewportPF m_glViewport = nullptr;
+};
+
+class VideoSurfaceGL : public VideoSurfaceProvider
+{
+public:
+ VideoSurfaceGL(VideoRendererGL* renderer, QObject* parent = nullptr);
+
+private:
+ QSGNode *updatePaintNode(QQuickItem* item, QSGNode *, QQuickItem::UpdatePaintNodeData *) override;
+
+private:
+ VideoRendererGL* m_renderer = nullptr;
+ QSharedPointer<QSGTexture> m_displayTexture;
+};
+
+
+
+#endif // VIDEORENDERERGL_HPP
--
2.19.1
More information about the vlc-devel
mailing list