diff options
Diffstat (limited to 'src/qtmultimediaquicktools')
10 files changed, 200 insertions, 53 deletions
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index 32166502d..a948a5218 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -138,6 +138,7 @@ QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) : { initResource(); setFlag(ItemHasContents, true); + createBackend(nullptr); } QDeclarativeVideoOutput::~QDeclarativeVideoOutput() @@ -148,6 +149,23 @@ QDeclarativeVideoOutput::~QDeclarativeVideoOutput() } /*! + \qmlproperty object QtMultimedia::VideoOutput::videoSurface + \since 5.15 + + This property holds the underlaying video surface that can be used + to render the video frames to this VideoOutput element. + It is similar to setting a QObject with \c videoSurface property as a source, + where this video surface will be set. + + \sa source +*/ + +QAbstractVideoSurface *QDeclarativeVideoOutput::videoSurface() const +{ + return m_backend ? m_backend->videoSurface() : nullptr; +} + +/*! \qmlproperty variant QtMultimedia::VideoOutput::source This property holds the source item providing the video frames like MediaPlayer or Camera. @@ -206,21 +224,10 @@ void QDeclarativeVideoOutput::setSource(QObject *source) } m_sourceType = MediaObjectSource; -#if QT_CONFIG(opengl) } else if (metaObject->indexOfProperty("videoSurface") != -1) { - // Make sure our backend is a QDeclarativeVideoRendererBackend - m_backend.reset(); - createBackend(0); - Q_ASSERT(m_backend); -#ifndef QT_NO_DYNAMIC_CAST - Q_ASSERT(dynamic_cast<QDeclarativeVideoRendererBackend *>(m_backend.data())); -#endif - QAbstractVideoSurface * const surface = m_backend->videoSurface(); - Q_ASSERT(surface); m_source.data()->setProperty("videoSurface", - QVariant::fromValue<QAbstractVideoSurface*>(surface)); + QVariant::fromValue<QAbstractVideoSurface *>(videoSurface())); m_sourceType = VideoSurfaceSource; -#endif } else { m_sourceType = NoSource; } @@ -242,7 +249,8 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) const auto instances = videoBackendFactoryLoader()->instances(QLatin1String("declarativevideobackend")); for (QObject *instance : instances) { if (QDeclarativeVideoBackendFactoryInterface *plugin = qobject_cast<QDeclarativeVideoBackendFactoryInterface*>(instance)) { - m_backend.reset(plugin->create(this)); + if (!m_backend) + m_backend.reset(plugin->create(this)); if (m_backend && m_backend->init(service)) { backendAvailable = true; break; @@ -251,7 +259,8 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) } #if QT_CONFIG(opengl) if (!backendAvailable) { - m_backend.reset(new QDeclarativeVideoRendererBackend(this)); + if (!m_backend) + m_backend.reset(new QDeclarativeVideoRendererBackend(this)); if (m_backend->init(service)) backendAvailable = true; } @@ -293,9 +302,6 @@ void QDeclarativeVideoOutput::_q_updateMediaObject() if (m_mediaObject.data() == mediaObject) return; - if (m_sourceType != VideoSurfaceSource) - m_backend.reset(); - m_mediaObject.clear(); m_service.clear(); @@ -368,6 +374,8 @@ void QDeclarativeVideoOutput::_q_updateNativeSize() if (!m_backend) return; + m_geometryDirty = true; + QSize size = m_backend->nativeSize(); if (!qIsDefaultAspect(m_orientation)) { size.transpose(); @@ -376,8 +384,6 @@ void QDeclarativeVideoOutput::_q_updateNativeSize() if (m_nativeSize != size) { m_nativeSize = size; - m_geometryDirty = true; - setImplicitWidth(size.width()); setImplicitHeight(size.height()); @@ -415,9 +421,8 @@ void QDeclarativeVideoOutput::_q_updateGeometry() } if (m_backend) { - if (!m_backend->videoSurface() || m_backend->videoSurface()->isActive()) - m_backend->updateGeometry(); - else + m_backend->updateGeometry(); + if (m_backend->videoSurface() && !m_backend->videoSurface()->isActive()) m_geometryDirty = true; } diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h index 8ea0dc338..d14731c91 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h @@ -67,6 +67,7 @@ class QMediaObject; class QMediaService; class QDeclarativeVideoBackend; class QVideoOutputOrientationHandler; +class QAbstractVideoSurface; class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem { @@ -80,6 +81,7 @@ class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem Q_PROPERTY(QRectF contentRect READ contentRect NOTIFY contentRectChanged) Q_PROPERTY(QQmlListProperty<QAbstractVideoFilter> filters READ filters); Q_PROPERTY(FlushMode flushMode READ flushMode WRITE setFlushMode NOTIFY flushModeChanged REVISION 13) + Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface CONSTANT REVISION 15) Q_ENUMS(FlushMode) Q_ENUMS(FillMode) @@ -102,6 +104,8 @@ public: QDeclarativeVideoOutput(QQuickItem *parent = 0); ~QDeclarativeVideoOutput(); + QAbstractVideoSurface *videoSurface() const; + QObject *source() const { return m_source.data(); } void setSource(QObject *source); diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index 863cefa4e..bdfa23dfb 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -46,7 +46,6 @@ #include <QtCore/qloggingcategory.h> #include <private/qmediapluginloader_p.h> #include <private/qsgvideonode_p.h> -#include <private/qvideoframe_p.h> #include <QtGui/QOpenGLContext> #include <QtQuick/QQuickWindow> @@ -304,7 +303,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, if (!runnable) continue; - QVideoFilterRunnable::RunFlags flags = 0; + QVideoFilterRunnable::RunFlags flags; if (i == m_filters.count() - 1) flags |= QVideoFilterRunnable::LastInChain; @@ -363,7 +362,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, videoNode->setTexturedRectGeometry(m_renderedRect, m_sourceTextureRect, qNormalizedOrientation(q->orientation())); if (m_frameChanged) { - QSGVideoNode::FrameFlags flags = 0; + QSGVideoNode::FrameFlags flags; if (isFrameModified) flags |= QSGVideoNode::FrameFiltered; videoNode->setCurrentFrame(m_frame, flags); @@ -372,7 +371,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, || q->flushMode() == QDeclarativeVideoOutput::LastFrame) { m_frameOnFlush = m_surfaceFormat.handleType() == QAbstractVideoBuffer::NoHandle ? m_frame - : qt_imageFromVideoFrame(m_frame); + : m_frame.image(); } //don't keep the frame for more than really necessary diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp index 473a4144f..bac143b43 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp @@ -53,6 +53,13 @@ QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_Texture::supportedPixelForma { QList<QVideoFrame::PixelFormat> pixelFormats; +#ifdef Q_OS_MACOS + if (handleType == QAbstractVideoBuffer::GLTextureRectangleHandle) { + pixelFormats.append(QVideoFrame::Format_BGR32); + pixelFormats.append(QVideoFrame::Format_BGRA32); + } +#endif + if (handleType == QAbstractVideoBuffer::GLTextureHandle) { pixelFormats.append(QVideoFrame::Format_RGB565); pixelFormats.append(QVideoFrame::Format_RGB32); @@ -82,8 +89,6 @@ public: QSGVideoMaterialShader_Texture() : QSGMaterialShader() { - setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/monoplanarvideo.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo.frag")); } void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; @@ -109,10 +114,20 @@ protected: int m_id_opacity; }; -class QSGVideoMaterialShader_Texture_swizzle : public QSGVideoMaterialShader_Texture +class QSGVideoMaterialShader_Texture_2D : public QSGVideoMaterialShader_Texture { public: - QSGVideoMaterialShader_Texture_swizzle(bool hasAlpha) + QSGVideoMaterialShader_Texture_2D() + { + setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/monoplanarvideo.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo.frag")); + } +}; + +class QSGVideoMaterialShader_Texture_2D_swizzle : public QSGVideoMaterialShader_Texture_2D +{ +public: + QSGVideoMaterialShader_Texture_2D_swizzle(bool hasAlpha) : m_hasAlpha(hasAlpha) { setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag")); @@ -120,14 +135,13 @@ public: protected: void initialize() override { - QSGVideoMaterialShader_Texture::initialize(); + QSGVideoMaterialShader_Texture_2D::initialize(); program()->setUniformValue(program()->uniformLocation("hasAlpha"), GLboolean(m_hasAlpha)); } int m_hasAlpha; }; - class QSGVideoMaterial_Texture : public QSGMaterial { public: @@ -149,12 +163,6 @@ public: return needsSwizzling() ? &swizzleType : &normalType; } - QSGMaterialShader *createShader() const override { - const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; - return needsSwizzling() ? new QSGVideoMaterialShader_Texture_swizzle(hasAlpha) - : new QSGVideoMaterialShader_Texture; - } - int compare(const QSGMaterial *other) const override { const QSGVideoMaterial_Texture *m = static_cast<const QSGVideoMaterial_Texture *>(other); @@ -179,9 +187,42 @@ public: void setVideoFrame(const QVideoFrame &frame) { QMutexLocker lock(&m_frameMutex); m_frame = frame; + m_textureSize = frame.size(); + } + + virtual void bind() = 0; + + QVideoFrame m_frame; + QMutex m_frameMutex; + QSize m_textureSize; + QVideoSurfaceFormat m_format; + GLuint m_textureId; + qreal m_opacity; + +protected: + bool needsSwizzling() const { + return !QMediaOpenGLHelper::isANGLE() + && (m_format.pixelFormat() == QVideoFrame::Format_RGB32 + || m_format.pixelFormat() == QVideoFrame::Format_ARGB32); + } +}; + +class QSGVideoMaterial_Texture_2D : public QSGVideoMaterial_Texture +{ +public: + QSGVideoMaterial_Texture_2D(const QVideoSurfaceFormat &format) : + QSGVideoMaterial_Texture(format) + { } - void bind() + QSGMaterialShader *createShader() const override + { + const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32; + return needsSwizzling() ? new QSGVideoMaterialShader_Texture_2D_swizzle(hasAlpha) + : new QSGVideoMaterialShader_Texture_2D; + } + + void bind() override { QMutexLocker lock(&m_frameMutex); if (m_frame.isValid()) { @@ -197,28 +238,84 @@ public: m_textureId = 0; } } +}; + +#ifdef Q_OS_MACOS +class QSGVideoMaterialShader_Texture_Rectangle : public QSGVideoMaterialShader_Texture +{ +public: + QSGVideoMaterialShader_Texture_Rectangle() + { + setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/rectsampler.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rectsampler_rgb.frag")); + } - QVideoFrame m_frame; - QMutex m_frameMutex; - QSize m_textureSize; - QVideoSurfaceFormat m_format; - GLuint m_textureId; - qreal m_opacity; + void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override + { + QSGVideoMaterial_Texture *mat = static_cast<QSGVideoMaterial_Texture *>(newMaterial); + QVector2D size(mat->m_textureSize.width(), mat->m_textureSize.height()); + program()->setUniformValue(m_id_videoSize, size); -private: - bool needsSwizzling() const { - return !QMediaOpenGLHelper::isANGLE() - && (m_format.pixelFormat() == QVideoFrame::Format_RGB32 - || m_format.pixelFormat() == QVideoFrame::Format_ARGB32); + QSGVideoMaterialShader_Texture::updateState(state, newMaterial, oldMaterial); } + +protected: + void initialize() override + { + QSGVideoMaterialShader_Texture::initialize(); + m_id_videoSize = program()->uniformLocation("qt_videoSize"); + } + + int m_id_videoSize; }; +class QSGVideoMaterial_Texture_Rectangle : public QSGVideoMaterial_Texture +{ +public: + QSGVideoMaterial_Texture_Rectangle(const QVideoSurfaceFormat &format) : + QSGVideoMaterial_Texture(format) + { + } + + QSGMaterialShader *createShader() const override + { + Q_ASSERT(!needsSwizzling()); + return new QSGVideoMaterialShader_Texture_Rectangle; + } + + void bind() override + { + QMutexLocker lock(&m_frameMutex); + if (m_frame.isValid()) { + m_textureId = m_frame.handle().toUInt(); + QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions(); + functions->glActiveTexture(GL_TEXTURE0); + functions->glBindTexture(GL_TEXTURE_RECTANGLE, m_textureId); + + functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else { + m_textureId = 0; + } + } +}; +#endif QSGVideoNode_Texture::QSGVideoNode_Texture(const QVideoSurfaceFormat &format) : m_format(format) { setFlag(QSGNode::OwnsMaterial); - m_material = new QSGVideoMaterial_Texture(format); + +#ifdef Q_OS_MACOS + if (format.handleType() == QAbstractVideoBuffer::GLTextureRectangleHandle) + m_material = new QSGVideoMaterial_Texture_Rectangle(format); +#endif + + if (!m_material) + m_material = new QSGVideoMaterial_Texture_2D(format); + setMaterial(m_material); } diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture_p.h b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h index 12685dd24..21c905bd5 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_texture_p.h +++ b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h @@ -74,7 +74,7 @@ public: private: QVideoSurfaceFormat m_format; - QSGVideoMaterial_Texture *m_material; + QSGVideoMaterial_Texture *m_material = nullptr; QVideoFrame m_frame; }; diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc index b8180e31f..86523e771 100644 --- a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc +++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc @@ -11,7 +11,6 @@ <file>shaders/triplanaryuvvideo.vert</file> <file>shaders/uyvyvideo.frag</file> <file>shaders/yuyvvideo.frag</file> - <file>shaders/monoplanarvideo_core.vert</file> <file>shaders/rgbvideo_core.frag</file> <file>shaders/rgbvideo_swizzle_core.frag</file> @@ -23,5 +22,9 @@ <file>shaders/triplanaryuvvideo_core.vert</file> <file>shaders/uyvyvideo_core.frag</file> <file>shaders/yuyvvideo_core.frag</file> + <file>shaders/rectsampler.vert</file> + <file>shaders/rectsampler_rgb.frag</file> + <file>shaders/rectsampler_core.vert</file> + <file>shaders/rectsampler_rgb_core.frag</file> </qresource> </RCC> diff --git a/src/qtmultimediaquicktools/shaders/rectsampler.vert b/src/qtmultimediaquicktools/shaders/rectsampler.vert new file mode 100644 index 000000000..762ec7e7e --- /dev/null +++ b/src/qtmultimediaquicktools/shaders/rectsampler.vert @@ -0,0 +1,10 @@ +uniform highp mat4 qt_Matrix; +uniform highp vec2 qt_videoSize; +attribute highp vec4 qt_VertexPosition; +attribute highp vec2 qt_VertexTexCoord; +varying highp vec2 qt_TexCoord; + +void main() { + qt_TexCoord = vec2(qt_VertexTexCoord.x * qt_videoSize.x, qt_VertexTexCoord.y * qt_videoSize.y); + gl_Position = qt_Matrix * qt_VertexPosition; +} diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_core.vert b/src/qtmultimediaquicktools/shaders/rectsampler_core.vert new file mode 100644 index 000000000..f0fe02349 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders/rectsampler_core.vert @@ -0,0 +1,11 @@ +#version 150 core +uniform highp mat4 qt_Matrix; +uniform highp vec2 qt_videoSize; +in highp vec4 qt_VertexPosition; +in highp vec2 qt_VertexTexCoord; +out highp vec2 qt_TexCoord; + +void main() { + qt_TexCoord = vec2(qt_VertexTexCoord.x * qt_videoSize.x, qt_VertexTexCoord.y * qt_videoSize.y); + gl_Position = qt_Matrix * qt_VertexPosition; +} diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag b/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag new file mode 100644 index 000000000..2a30f7c3d --- /dev/null +++ b/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag @@ -0,0 +1,8 @@ +uniform sampler2DRect rgbTexture; +uniform lowp float opacity; +varying highp vec2 qt_TexCoord; + +void main() +{ + gl_FragColor = texture2DRect(rgbTexture, qt_TexCoord) * opacity; +} diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag b/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag new file mode 100644 index 000000000..17f306456 --- /dev/null +++ b/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag @@ -0,0 +1,10 @@ +#version 150 core +uniform sampler2DRect rgbTexture; +uniform lowp float opacity; +in highp vec2 qt_TexCoord; +out vec4 fragColor; + +void main() +{ + fragColor = texture(rgbTexture, qt_TexCoord) * opacity; +} |