diff options
21 files changed, 7 insertions, 1496 deletions
diff --git a/examples/multimedia/video/qmlvideofilter_opencl/CMakeLists.txt b/examples/multimedia/video/qmlvideofilter_opencl/CMakeLists.txt deleted file mode 100644 index a3c1d6a19..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -# Generated from qmlvideofilter_opencl.pro. - -cmake_minimum_required(VERSION 3.14) -project(qmlvideofilter_opencl LANGUAGES CXX) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/multimedia/video/qmlvideofilter_opencl") - -find_package(Qt6 COMPONENTS Core) -find_package(Qt6 COMPONENTS Gui) -find_package(Qt6 COMPONENTS Quick) -find_package(Qt6 COMPONENTS Multimedia) - -qt_add_executable(qmlvideofilter_opencl - main.cpp - rgbframehelper.h -) -set_target_properties(qmlvideofilter_opencl PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE -) -target_link_libraries(qmlvideofilter_opencl PUBLIC - Qt::Core - Qt::Gui - Qt::Multimedia - Qt::Quick -) - - -# Resources: -set(qmlvideofilter_opencl_resource_files - "main.qml" -) - -qt6_add_resources(qmlvideofilter_opencl "qmlvideofilter_opencl" - PREFIX - "/" - FILES - ${qmlvideofilter_opencl_resource_files} -) - -if(MACOS) - target_link_libraries(qmlvideofilter_opencl PUBLIC - "-framework OpenCL" - ) -endif() - -if(UNIX AND NOT MACOS) - target_link_libraries(qmlvideofilter_opencl PUBLIC - OpenCL - ) -endif() - -if(WIN32 AND NOT WINRT) - target_link_libraries(qmlvideofilter_opencl PUBLIC - OpenCL - opengl32 - ) -endif() - -install(TARGETS qmlvideofilter_opencl - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/multimedia/video/qmlvideofilter_opencl/README b/examples/multimedia/video/qmlvideofilter_opencl/README deleted file mode 100644 index cc351e430..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/README +++ /dev/null @@ -1,15 +0,0 @@ -This example performs some simple OpenCL operations on camera or video input -which is assumed to be provided in RGB format. The OpenCL operation is done on -an OpenGL texture using CL-GL interop, without any further readbacks or copies -(except for the initial texture upload, when necessary). - -Currently OS X, Windows with real OpenGL (opengl32.dll) and Linux (GLX) are -supported. Note that an OpenCL implementation with GPU support is required. The -platform and device selection logic supports NVIDIA, AMD and Intel. Porting to -other platforms is probably simple, see clCreateContextFromType. - -YUV formats are not supported in this example. This is probably not an issue an -OS X and Windows, but will most likely disable the example on Linux. - -Pass the name of a video file to perform video playback or launch without -arguments to use the camera. diff --git a/examples/multimedia/video/qmlvideofilter_opencl/main.cpp b/examples/multimedia/video/qmlvideofilter_opencl/main.cpp deleted file mode 100644 index 2ee2d8bf4..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/main.cpp +++ /dev/null @@ -1,526 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Multimedia module. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QGuiApplication> -#include <QQuickView> -#include <QOpenGLContext> -#include <QOpenGLFunctions> -#include <QAbstractVideoFilter> -#include <QQmlContext> -#include <QFileInfo> - -#ifdef Q_OS_OSX -#include <OpenCL/opencl.h> -#include <OpenGL/OpenGL.h> -#else -#include <CL/opencl.h> -#endif - -#ifdef Q_OS_LINUX -#include <QtPlatformHeaders/QGLXNativeContext> -#endif - -#include "rgbframehelper.h" - -static const char *openclSrc = - "__constant sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;\n" - "__kernel void Emboss(__read_only image2d_t imgIn, __write_only image2d_t imgOut, float factor) {\n" - " const int2 pos = { get_global_id(0), get_global_id(1) };\n" - " float4 diff = read_imagef(imgIn, sampler, pos + (int2)(1,1)) - read_imagef(imgIn, sampler, pos - (int2)(1,1));\n" - " float color = (diff.x + diff.y + diff.z) / factor + 0.5f;\n" - " write_imagef(imgOut, pos, (float4)(color, color, color, 1.0f));\n" - "}\n"; - -class CLFilter : public QAbstractVideoFilter -{ - Q_OBJECT - Q_PROPERTY(qreal factor READ factor WRITE setFactor NOTIFY factorChanged) - -public: - CLFilter() : m_factor(1) { } - qreal factor() const { return m_factor; } - void setFactor(qreal v); - - QVideoFilterRunnable *createFilterRunnable() override; - -signals: - void factorChanged(); - -private: - qreal m_factor; -}; - -class CLFilterRunnable : public QVideoFilterRunnable -{ -public: - CLFilterRunnable(CLFilter *filter); - ~CLFilterRunnable(); - QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) override; - -private: - void releaseTextures(); - uint newTexture(); - - CLFilter *m_filter; - QSize m_size; - uint m_tempTexture; - uint m_outTexture; - uint m_lastInputTexture; - cl_context m_clContext; - cl_device_id m_clDeviceId; - cl_mem m_clImage[2]; - cl_command_queue m_clQueue; - cl_program m_clProgram; - cl_kernel m_clKernel; -}; - -QVideoFilterRunnable *CLFilter::createFilterRunnable() -{ - return new CLFilterRunnable(this); -} - -CLFilterRunnable::CLFilterRunnable(CLFilter *filter) : - m_filter(filter), - m_tempTexture(0), - m_outTexture(0), - m_lastInputTexture(0), - m_clContext(0), - m_clQueue(0), - m_clProgram(0), - m_clKernel(0) -{ - m_clImage[0] = m_clImage[1] = 0; - - // Set up OpenCL. - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - cl_uint n; - cl_int err = clGetPlatformIDs(0, 0, &n); - if (err != CL_SUCCESS) { - qWarning("Failed to get platform ID count (error %d)", err); - if (err == -1001) { - qDebug("Could not find OpenCL implementation. ICD missing?" -#ifdef Q_OS_LINUX - " Check /etc/OpenCL/vendors." -#endif - ); - } - return; - } - if (n == 0) { - qWarning("No OpenCL platform found"); - return; - } - QList<cl_platform_id> platformIds; - platformIds.resize(n); - if (clGetPlatformIDs(n, platformIds.data(), 0) != CL_SUCCESS) { - qWarning("Failed to get platform IDs"); - return; - } - cl_platform_id platform = platformIds[0]; - const char *vendor = (const char *) f->glGetString(GL_VENDOR); - qDebug("GL_VENDOR: %s", vendor); - const bool isNV = vendor && strstr(vendor, "NVIDIA"); - const bool isIntel = vendor && strstr(vendor, "Intel"); - const bool isAMD = vendor && strstr(vendor, "ATI"); - qDebug("Found %u OpenCL platforms:", n); - for (cl_uint i = 0; i < n; ++i) { - QByteArray name; - name.resize(1024); - clGetPlatformInfo(platformIds[i], CL_PLATFORM_NAME, name.size(), name.data(), 0); - qDebug("Platform %p: %s", platformIds[i], name.constData()); - // Running with an OpenCL platform without GPU support is not going - // to cut it. In practice we want the platform for the GPU which we - // are using with OpenGL. - if (isNV && name.contains(QByteArrayLiteral("NVIDIA"))) - platform = platformIds[i]; - else if (isIntel && name.contains(QByteArrayLiteral("Intel"))) - platform = platformIds[i]; - else if (isAMD && name.contains(QByteArrayLiteral("AMD"))) - platform = platformIds[i]; - } - qDebug("Using platform %p", platform); - - // Set up the context with OpenCL/OpenGL interop. -#if defined (Q_OS_OSX) - cl_context_properties contextProps[] = { CL_CONTEXT_PROPERTY_USE_CGL_SHAREGROUP_APPLE, - (cl_context_properties) CGLGetShareGroup(CGLGetCurrentContext()), - 0 }; -#elif defined(Q_OS_WIN) - cl_context_properties contextProps[] = { CL_CONTEXT_PLATFORM, (cl_context_properties) platform, - CL_GL_CONTEXT_KHR, (cl_context_properties) wglGetCurrentContext(), - CL_WGL_HDC_KHR, (cl_context_properties) wglGetCurrentDC(), - 0 }; -#elif defined(Q_OS_LINUX) - QVariant nativeGLXHandle = QOpenGLContext::currentContext()->nativeHandle(); - QGLXNativeContext nativeGLXContext; - if (!nativeGLXHandle.isNull() && nativeGLXHandle.canConvert<QGLXNativeContext>()) - nativeGLXContext = nativeGLXHandle.value<QGLXNativeContext>(); - else - qWarning("Failed to get the underlying GLX context from the current QOpenGLContext"); - cl_context_properties contextProps[] = { CL_CONTEXT_PLATFORM, (cl_context_properties) platform, - CL_GL_CONTEXT_KHR, (cl_context_properties) nativeGLXContext.context(), - CL_GLX_DISPLAY_KHR, (cl_context_properties) glXGetCurrentDisplay(), - 0 }; -#endif - - m_clContext = clCreateContextFromType(contextProps, CL_DEVICE_TYPE_GPU, 0, 0, &err); - if (!m_clContext) { - qWarning("Failed to create OpenCL context: %d", err); - return; - } - - // Get the GPU device id -#if defined(Q_OS_OSX) - // On OS X, get the "online" device/GPU. This is required for OpenCL/OpenGL context sharing. - err = clGetGLContextInfoAPPLE(m_clContext, CGLGetCurrentContext(), - CL_CGL_DEVICE_FOR_CURRENT_VIRTUAL_SCREEN_APPLE, - sizeof(cl_device_id), &m_clDeviceId, 0); - if (err != CL_SUCCESS) { - qWarning("Failed to get OpenCL device for current screen: %d", err); - return; - } -#else - clGetGLContextInfoKHR_fn getGLContextInfo = (clGetGLContextInfoKHR_fn) clGetExtensionFunctionAddress("clGetGLContextInfoKHR"); - if (!getGLContextInfo || getGLContextInfo(contextProps, CL_CURRENT_DEVICE_FOR_GL_CONTEXT_KHR, - sizeof(cl_device_id), &m_clDeviceId, 0) != CL_SUCCESS) { - err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &m_clDeviceId, 0); - if (err != CL_SUCCESS) { - qWarning("Failed to get OpenCL device: %d", err); - return; - } - } -#endif - - m_clQueue = clCreateCommandQueue(m_clContext, m_clDeviceId, 0, &err); - if (!m_clQueue) { - qWarning("Failed to create OpenCL command queue: %d", err); - return; - } - // Build the program. - m_clProgram = clCreateProgramWithSource(m_clContext, 1, &openclSrc, 0, &err); - if (!m_clProgram) { - qWarning("Failed to create OpenCL program: %d", err); - return; - } - if (clBuildProgram(m_clProgram, 1, &m_clDeviceId, 0, 0, 0) != CL_SUCCESS) { - qWarning("Failed to build OpenCL program"); - QByteArray log; - log.resize(2048); - clGetProgramBuildInfo(m_clProgram, m_clDeviceId, CL_PROGRAM_BUILD_LOG, log.size(), log.data(), 0); - qDebug("Build log: %s", log.constData()); - return; - } - m_clKernel = clCreateKernel(m_clProgram, "Emboss", &err); - if (!m_clKernel) { - qWarning("Failed to create emboss OpenCL kernel: %d", err); - return; - } -} - -CLFilterRunnable::~CLFilterRunnable() -{ - releaseTextures(); - if (m_clKernel) - clReleaseKernel(m_clKernel); - if (m_clProgram) - clReleaseProgram(m_clProgram); - if (m_clQueue) - clReleaseCommandQueue(m_clQueue); - if (m_clContext) - clReleaseContext(m_clContext); -} - -void CLFilterRunnable::releaseTextures() -{ - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - if (m_tempTexture) - f->glDeleteTextures(1, &m_tempTexture); - if (m_outTexture) - f->glDeleteTextures(1, &m_outTexture); - m_tempTexture = m_outTexture = m_lastInputTexture = 0; - if (m_clImage[0]) - clReleaseMemObject(m_clImage[0]); - if (m_clImage[1]) - clReleaseMemObject(m_clImage[1]); - m_clImage[0] = m_clImage[1] = 0; -} - -uint CLFilterRunnable::newTexture() -{ - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - GLuint texture; - f->glGenTextures(1, &texture); - f->glBindTexture(GL_TEXTURE_2D, texture); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_size.width(), m_size.height(), - 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); - return texture; -} - -QVideoFrame CLFilterRunnable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) -{ - Q_UNUSED(surfaceFormat); - Q_UNUSED(flags); - - // This example supports RGB data only, either in system memory (typical with cameras on all - // platforms) or as an OpenGL texture (e.g. video playback on OS X). - // The latter is the fast path where everything happens on GPU. THe former involves a texture upload. - - if (!input->isValid() - || (input->handleType() != QVideoFrame::NoHandle - && input->handleType() != QVideoFrame::GLTextureHandle)) { - qWarning("Invalid input format"); - return *input; - } - - if (input->pixelFormat() == QVideoSurfaceFormat::Format_YUV420P - || input->pixelFormat() == QVideoSurfaceFormat::Format_YV12) { - qWarning("YUV data is not supported"); - return *input; - } - - if (m_size != input->size()) { - releaseTextures(); - m_size = input->size(); - } - - // Create a texture from the image data. - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - GLuint texture; - if (input->handleType() == QVideoFrame::NoHandle) { - // Upload. - if (m_tempTexture) - f->glBindTexture(GL_TEXTURE_2D, m_tempTexture); - else - m_tempTexture = newTexture(); - input->map(QVideoFrame::ReadOnly); - // glTexImage2D only once and use TexSubImage later on. This avoids the need - // to recreate the CL image object on every frame. - f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_size.width(), m_size.height(), - GL_RGBA, GL_UNSIGNED_BYTE, input->bits()); - input->unmap(); - texture = m_tempTexture; - } else { - // Already an OpenGL texture. - texture = input->handle().toUInt(); - f->glBindTexture(GL_TEXTURE_2D, texture); - // Unlike on the other branch, the input texture may change, so m_clImage[0] may need to be recreated. - if (m_lastInputTexture && m_lastInputTexture != texture && m_clImage[0]) { - clReleaseMemObject(m_clImage[0]); - m_clImage[0] = 0; - } - m_lastInputTexture = texture; - } - - // OpenCL image objects cannot be read and written at the same time. So use - // a separate texture for the result. - if (!m_outTexture) - m_outTexture = newTexture(); - - // Create the image objects if not yet done. - cl_int err; - if (!m_clImage[0]) { - m_clImage[0] = clCreateFromGLTexture2D(m_clContext, CL_MEM_READ_ONLY, GL_TEXTURE_2D, 0, texture, &err); - if (!m_clImage[0]) { - qWarning("Failed to create OpenGL image object from OpenGL texture: %d", err); - return *input; - } - cl_image_format fmt; - if (clGetImageInfo(m_clImage[0], CL_IMAGE_FORMAT, sizeof(fmt), &fmt, 0) != CL_SUCCESS) { - qWarning("Failed to query image format"); - return *input; - } - if (fmt.image_channel_order != CL_RGBA) - qWarning("OpenCL image is not RGBA, expect errors"); - } - if (!m_clImage[1]) { - m_clImage[1] = clCreateFromGLTexture2D(m_clContext, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, m_outTexture, &err); - if (!m_clImage[1]) { - qWarning("Failed to create output OpenGL image object from OpenGL texture: %d", err); - return *input; - } - } - - // We are all set. Queue acquiring the image objects. - f->glFinish(); - clEnqueueAcquireGLObjects(m_clQueue, 2, m_clImage, 0, 0, 0); - - // Set up the kernel arguments. - clSetKernelArg(m_clKernel, 0, sizeof(cl_mem), &m_clImage[0]); - clSetKernelArg(m_clKernel, 1, sizeof(cl_mem), &m_clImage[1]); - // Accessing dynamic properties on the filter element is simple: - cl_float factor = m_filter->factor(); - clSetKernelArg(m_clKernel, 2, sizeof(cl_float), &factor); - - // And queue the kernel. - const size_t workSize[] = { size_t(m_size.width()), size_t(m_size.height()) }; - err = clEnqueueNDRangeKernel(m_clQueue, m_clKernel, 2, 0, workSize, 0, 0, 0, 0); - if (err != CL_SUCCESS) - qWarning("Failed to enqueue kernel: %d", err); - - // Return the texture from our output image object. - // We return a texture even when the original video frame had pixel data in system memory. - // Qt Multimedia is smart enough to handle this. Once the data is on the GPU, it stays there. No readbacks, no copies. - clEnqueueReleaseGLObjects(m_clQueue, 2, m_clImage, 0, 0, 0); - clFinish(m_clQueue); - return frameFromTexture(m_outTexture, m_size, input->pixelFormat()); -} - -// InfoFilter will just provide some information about the video frame, to demonstrate -// passing arbitrary data to QML via its finished() signal. -class InfoFilter : public QAbstractVideoFilter -{ - Q_OBJECT - -public: - QVideoFilterRunnable *createFilterRunnable() override; - -signals: - void finished(QObject *result); - -private: - friend class InfoFilterRunnable; -}; - -class InfoFilterRunnable : public QVideoFilterRunnable -{ -public: - InfoFilterRunnable(InfoFilter *filter) : m_filter(filter) { } - QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) override; - -private: - InfoFilter *m_filter; -}; - -class InfoFilterResult : public QObject -{ - Q_OBJECT - Q_PROPERTY(QSize frameResolution READ frameResolution) - Q_PROPERTY(QString handleType READ handleType) - Q_PROPERTY(int pixelFormat READ pixelFormat) - -public: - InfoFilterResult() : m_pixelFormat(0) { } - QSize frameResolution() const { return m_frameResolution; } - QString handleType() const { return m_handleType; } - int pixelFormat() const { return m_pixelFormat; } - -private: - QSize m_frameResolution; - QString m_handleType; - int m_pixelFormat; - friend class InfoFilterRunnable; -}; - -void CLFilter::setFactor(qreal v) -{ - if (m_factor != v) { - m_factor = v; - emit factorChanged(); - } -} - -QVideoFilterRunnable *InfoFilter::createFilterRunnable() -{ - return new InfoFilterRunnable(this); -} - -QVideoFrame InfoFilterRunnable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) -{ - Q_UNUSED(surfaceFormat); - Q_UNUSED(flags); - InfoFilterResult *result = new InfoFilterResult; - result->m_frameResolution = input->size(); - switch (input->handleType()) { - case QVideoFrame::NoHandle: - result->m_handleType = QLatin1String("pixel data"); - result->m_pixelFormat = input->pixelFormat(); - break; - case QVideoFrame::GLTextureHandle: - result->m_handleType = QLatin1String("OpenGL texture"); - break; - default: - result->m_handleType = QLatin1String("unknown"); - break; - } - emit m_filter->finished(result); // parent-less QObject -> ownership transferred to the JS engine - return *input; -} - -int main(int argc, char **argv) -{ -#ifdef Q_OS_WIN // avoid ANGLE on Windows - QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); -#endif - QGuiApplication app(argc, argv); - - qmlRegisterType<CLFilter>("qmlvideofilter.cl.test", 1, 0, "CLFilter"); - qmlRegisterType<InfoFilter>("qmlvideofilter.cl.test", 1, 0, "InfoFilter"); - - QQuickView view; - QString fn; - if (argc > 1) { - fn = QUrl::fromLocalFile(QFileInfo(QString::fromUtf8(argv[1])).absoluteFilePath()).toString(); - qDebug("Playing video %s", qPrintable(fn)); - } else { - qDebug("No video file specified, using camera instead."); - } - view.rootContext()->setContextProperty("videoFilename", fn); - view.setSource(QUrl("qrc:///main.qml")); - - view.show(); - - return app.exec(); -} - -#include "main.moc" diff --git a/examples/multimedia/video/qmlvideofilter_opencl/main.qml b/examples/multimedia/video/qmlvideofilter_opencl/main.qml deleted file mode 100644 index 3d3205398..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/main.qml +++ /dev/null @@ -1,131 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Multimedia module. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.0 -import QtMultimedia 5.5 -import qmlvideofilter.cl.test 1.0 - -Item { - width: 1024 - height: 768 - - Camera { - id: camera - } - - MediaPlayer { - id: player - autoPlay: true - source: videoFilename - } - - VideoOutput { - id: output - source: videoFilename !== "" ? player : camera - filters: [ infofilter, clfilter ] - anchors.fill: parent - } - - CLFilter { - id: clfilter - // Animate a property which is passed to the OpenCL kernel. - SequentialAnimation on factor { - loops: Animation.Infinite - NumberAnimation { - from: 1 - to: 20 - duration: 6000 - } - NumberAnimation { - from: 20 - to: 1 - duration: 3000 - } - } - } - - InfoFilter { - // This filter does not change the image. Instead, it provides some results calculated from the frame. - id: infofilter - onFinished: { - info.res = result.frameResolution.width + "x" + result.frameResolution.height; - info.type = result.handleType; - info.fmt = result.pixelFormat; - } - } - - Column { - Text { - font.pointSize: 20 - color: "green" - text: "Transformed with OpenCL on GPU\nClick to disable and enable the emboss filter" - } - Text { - font.pointSize: 12 - color: "green" - text: "Emboss factor " + Math.round(clfilter.factor) - visible: clfilter.active - } - Text { - id: info - font.pointSize: 12 - color: "green" - property string res - property string type - property int fmt - text: "Input resolution: " + res + " Input frame type: " + type + (fmt ? " Pixel format: " + fmt : "") - } - } - - MouseArea { - anchors.fill: parent - onClicked: clfilter.active = !clfilter.active - } -} diff --git a/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.pro b/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.pro deleted file mode 100644 index f7f191d2b..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.pro +++ /dev/null @@ -1,17 +0,0 @@ -TEMPLATE = app -TARGET = qmlvideofilter_opencl - -QT += quick multimedia - -SOURCES = main.cpp -HEADERS = rgbframehelper.h - -RESOURCES = qmlvideofilter_opencl.qrc -OTHER_FILES = main.qml - -target.path = $$[QT_INSTALL_EXAMPLES]/multimedia/video/qmlvideofilter_opencl -INSTALLS += target - -osx: LIBS += -framework OpenCL -unix: !osx: LIBS += -lOpenCL -win32:!winrt: LIBS += -lopengl32 -lOpenCL diff --git a/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.qrc b/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.qrc deleted file mode 100644 index 5f6483ac3..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/qmlvideofilter_opencl.qrc +++ /dev/null @@ -1,5 +0,0 @@ -<RCC> - <qresource prefix="/"> - <file>main.qml</file> - </qresource> -</RCC> diff --git a/examples/multimedia/video/qmlvideofilter_opencl/rgbframehelper.h b/examples/multimedia/video/qmlvideofilter_opencl/rgbframehelper.h deleted file mode 100644 index 79e577a40..000000000 --- a/examples/multimedia/video/qmlvideofilter_opencl/rgbframehelper.h +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the examples of the Qt Multimedia module. -** -** $QT_BEGIN_LICENSE:BSD$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** BSD License Usage -** Alternatively, you may use this file under the terms of the BSD license -** as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of The Qt Company Ltd nor the names of its -** contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef RGBFRAMEHELPER_H -#define RGBFRAMEHELPER_H - -#include <QImage> -#include <QAbstractVideoBuffer> -#include <QOpenGLContext> -#include <QOpenGLFunctions> -#include <QOpenGLFramebufferObject> - -/* - Returns a QImage that wraps the given video frame. - - This is suitable only for QVideoFrame::NoHandle frames with RGB (or BGR) - data. YUV is not supported here. - - The QVideoFrame must be mapped and kept mapped as long as the wrapping QImage - exists. - - As a convenience the function also supports frames with a handle type of - QVideoFrame::GLTextureHandle. This allows creating a system memory backed - QVideoFrame containing the image data from an OpenGL texture. However, readback is a - slow operation and may stall the GPU pipeline and should be avoided in production code. -*/ -QImage imageWrapper(const QVideoFrame &frame) -{ -#ifndef QT_NO_OPENGL - if (frame.handleType() == QVideoFrame::GLTextureHandle) { - // Slow and inefficient path. Ideally what's on the GPU should remain on the GPU, instead of readbacks like this. - QImage img(frame.width(), frame.height(), QImage::Format_RGBA8888); - GLuint textureId = frame.handle().toUInt(); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - QOpenGLFunctions *f = ctx->functions(); - GLuint fbo; - f->glGenFramebuffers(1, &fbo); - GLuint prevFbo; - f->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); - f->glBindFramebuffer(GL_FRAMEBUFFER, fbo); - f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); - f->glReadPixels(0, 0, frame.width(), frame.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); - f->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); - return img; - } else -#endif // QT_NO_OPENGL - { - if (!frame.isReadable()) { - qWarning("imageFromVideoFrame: No mapped image data available for read"); - return QImage(); - } - - QImage::Format fmt = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat()); - if (fmt != QImage::Format_Invalid) - return QImage(frame.bits(), frame.width(), frame.height(), fmt); - - qWarning("imageFromVideoFrame: No matching QImage format"); - } - - return QImage(); -} - -#ifndef QT_NO_OPENGL -class TextureBuffer : public QAbstractVideoBuffer -{ -public: - TextureBuffer(uint id) : QAbstractVideoBuffer(GLTextureHandle), m_id(id) { } - MapMode mapMode() const { return NotMapped; } - virtual MapData map(MapMode mode) { return {}; } - void unmap() { } - QVariant handle() const { return QVariant::fromValue<uint>(m_id); } - -private: - GLuint m_id; -}; -#endif // QT_NO_OPENGL - -/* - Creates and returns a new video frame wrapping the OpenGL texture textureId. The size - must be passed in size, together with the format of the underlying image data in - format. When the texture originates from a QImage, use - QVideoFrame::imageFormatFromPixelFormat() to get a suitable format. Ownership is not - altered, the new QVideoFrame will not destroy the texture. -*/ -QVideoFrame frameFromTexture(uint textureId, const QSize &size, QVideoSurfaceFormat::PixelFormat format) -{ -#ifndef QT_NO_OPENGL - return QVideoFrame(new TextureBuffer(textureId), size, format); -#else - return QVideoFrame(); -#endif // QT_NO_OPENGL -} - -#endif diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp index 663c24645..d98921dc1 100644 --- a/src/imports/multimedia/multimedia.cpp +++ b/src/imports/multimedia/multimedia.cpp @@ -44,7 +44,6 @@ #include "qsoundeffect.h" #include <private/qdeclarativevideooutput_p.h> -#include "qabstractvideofilter.h" #include "qdeclarativemultimediaglobal_p.h" #include "qdeclarativemediametadata_p.h" @@ -149,7 +148,6 @@ public: tr("CameraImageProcessing is provided by Camera")); qmlRegisterAnonymousType<QDeclarativeMediaMetaData>(uri, 5); - qmlRegisterAnonymousType<QAbstractVideoFilter>(uri, 5); // 5.13 types qmlRegisterType<QDeclarativeVideoOutput, 13>(uri, 5, 13, "VideoOutput"); diff --git a/src/imports/multimedia/plugins.qmltypes b/src/imports/multimedia/plugins.qmltypes index 6bd4664c5..14e0f5878 100644 --- a/src/imports/multimedia/plugins.qmltypes +++ b/src/imports/multimedia/plugins.qmltypes @@ -283,11 +283,6 @@ Module { } Component { name: "QAbstractListModel"; prototype: "QAbstractItemModel" } Component { - name: "QAbstractVideoFilter" - prototype: "QObject" - Property { name: "active"; type: "bool" } - } - Component { name: "QCamera" prototype: "QObject" Enum { @@ -1577,7 +1572,6 @@ Module { Property { name: "autoOrientation"; revision: 2; type: "bool" } Property { name: "sourceRect"; type: "QRectF"; isReadonly: true } Property { name: "contentRect"; type: "QRectF"; isReadonly: true } - Property { name: "filters"; type: "QAbstractVideoFilter"; isList: true; isReadonly: true } Property { name: "flushMode"; revision: 13; type: "FlushMode" } Property { name: "videoSurface" diff --git a/src/multimedia/CMakeLists.txt b/src/multimedia/CMakeLists.txt index 0de527d4b..f1f8a27a3 100644 --- a/src/multimedia/CMakeLists.txt +++ b/src/multimedia/CMakeLists.txt @@ -62,7 +62,6 @@ qt_internal_add_module(Multimedia recording/qmediaencodersettings.cpp recording/qmediaencodersettings.h recording/qmediarecorder.cpp recording/qmediarecorder.h recording/qmediarecorder_p.h video/qabstractvideobuffer.cpp video/qabstractvideobuffer_p.h - video/qabstractvideofilter.cpp video/qabstractvideofilter.h video/qimagevideobuffer.cpp video/qimagevideobuffer_p.h video/qmemoryvideobuffer.cpp video/qmemoryvideobuffer_p.h video/qvideoframe.cpp video/qvideoframe.h diff --git a/src/multimedia/video/qabstractvideofilter.cpp b/src/multimedia/video/qabstractvideofilter.cpp deleted file mode 100644 index 7bdee2177..000000000 --- a/src/multimedia/video/qabstractvideofilter.cpp +++ /dev/null @@ -1,319 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qabstractvideofilter.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QAbstractVideoFilter - \since 5.5 - \brief The QAbstractVideoFilter class represents a filter that is applied to the video frames - received by a VideoOutput type. - \inmodule QtMultimedia - - \ingroup multimedia - \ingroup multimedia_video - - QAbstractVideoFilter provides a convenient way for applications to run image - processing, computer vision algorithms or any generic transformation or - calculation on the output of a VideoOutput type, regardless of the source - (video or camera). By providing a simple interface it allows applications and - third parties to easily develop QML types that provide image processing - algorithms using popular frameworks like \l{http://opencv.org}{OpenCV}. Due to - the close integration with the final stages of the Qt Multimedia video - pipeline, accelerated and possibly zero-copy solutions are feasible too: for - instance, a plugin providing OpenCL-based algorithms can use OpenCL's OpenGL - interop to use the OpenGL textures created by a hardware accelerated video - decoder, without additional readbacks and copies. - - \note QAbstractVideoFilter is not always the best choice. To apply effects or - transformations using OpenGL shaders to the image shown on screen, the - standard Qt Quick approach of using ShaderEffect items in combination with - VideoOutput should be used. VideoFilter is not a replacement for this. It is - rather targeted for performing computations (that do not necessarily change - the image shown on screen) and computer vision algorithms provided by - external frameworks. - - QAbstractVideoFilter is meant to be subclassed. The subclasses are then registered to - the QML engine, so they can be used as a QML type. The list of filters are - assigned to a VideoOutput type via its \l{QtMultimedia::VideoOutput::filters}{filters} - property. - - A single filter represents one transformation or processing step on - a video frame. The output is a modified video frame, some arbitrary data or - both. For example, image transformations will result in a different image, - whereas an algorithm for detecting objects on an image will likely provide - a list of rectangles. - - Arbitrary data can be represented as properties on the QAbstractVideoFilter subclass - and on the QObject or QJSValue instances passed to its signals. What exactly - these properties and signals are, is up to the individual video - filters. Completion of the operations can be indicated by - signals. Computations that do not result in a modified image will pass the - input image through so that subsequent filters can be placed after them. - - Properties set on QAbstractVideoFilter serve as input to the computation, similarly - to how uniform values are specified in ShaderEffect types. The changed - property values are taken into use when the next video frame is processed. - - The typical usage is to subclass QAbstractVideoFilter and QVideoFilterRunnable: - - \badcode - class MyFilterRunnable : public QVideoFilterRunnable { - public: - QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) { ... } - }; - - class MyFilter : public QAbstractVideoFilter { - public: - QVideoFilterRunnable *createFilterRunnable() { return new MyFilterRunnable; } - signals: - void finished(QObject *result); - }; - - int main(int argc, char **argv) { - ... - qmlRegisterType<MyFilter>("my.uri", 1, 0, "MyFilter"); - ... - } - \endcode - - MyFilter is thus accessible from QML: - - \badcode - import my.uri 1.0 - - Camera { - id: camera - } - MyFilter { - id: filter - // set properties, they can also be animated - onFinished: console.log("results of the computation: " + result) - } - VideoOutput { - source: camera - filters: [ filter ] - anchors.fill: parent - } - \endcode - - This also allows providing filters in QML plugins, separately from the application. - - \sa VideoOutput, Camera, MediaPlayer, QVideoFilterRunnable -*/ - -/*! - \class QVideoFilterRunnable - \since 5.5 - \brief The QVideoFilterRunnable class represents the implementation of a filter - that owns all graphics and computational resources, and performs the actual filtering - or calculations. - \inmodule QtMultimedia - - \ingroup multimedia - \ingroup multimedia_video - - Video filters are split into QAbstractVideoFilter and corresponding QVideoFilterRunnable - instances, similar to QQuickItem and QSGNode. This is necessary to support - threaded rendering scenarios. When using the threaded render loop of the Qt - Quick scene graph, all rendering happens on a dedicated thread. - QVideoFilterRunnable instances always live on this thread and all its functions, - run(), the constructor, and the destructor, are guaranteed to be invoked on - that thread with the OpenGL context bound. QAbstractVideoFilter instances live on - the main (GUI) thread, like any other QObject and QQuickItem instances - created from QML. - - Once created, QVideoFilterRunnable instances are managed by Qt Multimedia and - will be automatically destroyed and recreated when necessary, for example - when the scene graph is invalidated or the QQuickWindow changes or is closed. - Creation happens via the QAbstractVideoFilter::createFilterRunnable() factory function. - - \sa QAbstractVideoFilter - */ - -/*! - \fn QVideoFrame QVideoFilterRunnable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) - - Reimplement this function to perform filtering or computation on the \a - input video frame. Like the constructor and destructor, this function is - always called on the render thread with the OpenGL context bound. - - Implementations that do not modify the video frame can simply return \a input. - - It is safe to access properties of the associated QAbstractVideoFilter instance from - this function. - - \a input will not be mapped, it is up to this function to call QVideoFrame::map() - and QVideoFrame::unmap() as necessary. - - \a surfaceFormat provides additional information, for example it can be used - to determine which way is up in the input image as that is important for - filters to operate on multiple platforms with multiple cameras. - - \a flags contains additional information about the filter's invocation. For - example the LastInChain flag indicates that the filter is the last in a - VideoOutput's associated filter list. This can be very useful in cases where - multiple filters are chained together and the work is performed on image data - in some custom format (for example a format specific to some computer vision - framework). To avoid conversion on every filter in the chain, all - intermediate filters can return a QVideoFrame hosting data in the custom - format. Only the last, where the flag is set, returns a QVideoFrame in a - format compatible with Qt. - - Filters that want to expose the results of their computation to Javascript - code in QML can declare their own custom signals in the QAbstractVideoFilter - subclass to indicate the completion of the operation. For filters that only - calculate some results and do not modify the video frame, it is also possible - to operate asynchronously. They can queue the necessary operations using the - compute API and return from this function without emitting any signals. The - signal indicating the completion is then emitted only when the compute API - indicates that the operations were done and the results are available. Note - that it is strongly recommended to represent the filter's output data as a - separate instance of QJSValue or a QObject-derived class which is passed as a - parameter to the signal and becomes exposed to the Javascript engine. In case - of QObject the ownership of this object is controlled by the standard QML - rules: if it has no parent, ownership is transferred to the Javascript engine, - otherwise it stays with the emitter. Note that the signal connection may be - queued,for example when using the threaded render loop of Qt Quick, and so the - object must stay valid for a longer time, destroying it right after calling - this function is not safe. Using a dedicated results object is guaranteed to - be safe even when using threaded rendering. The same is not necessarily true - for properties on the QAbstractVideoFilter instance itself: properties can - safely be read in run() since the gui thread is blocked during that time but - writing may become problematic. - - \note Avoid time consuming operations in this function as they block the - entire rendering of the application. - - \note The handleType() and pixelFormat() of \a input is completely up to the - video decoding backend on the platform in use. On some platforms different - forms of input are used depending on the graphics stack. For example, when - playing back videos on Windows with the WMF backend, QVideoFrame contains - OpenGL-wrapped Direct3D textures in case of using ANGLE, but regular pixel - data when using desktop OpenGL (opengl32.dll). Similarly, the video file - format will often decide if the data is RGB or YUV, but this may also depend - on the decoder and the configuration in use. The returned video frame does - not have to be in the same format as the input, for example a filter with an - input of a QVideoFrame backed by system memory can output a QVideoFrame with - an OpenGL texture handle. - - \sa QVideoFrame, QVideoSurfaceFormat - */ - -/*! - \enum QVideoFilterRunnable::RunFlag - - \value LastInChain Indicates that the filter runnable's associated QAbstractVideoFilter - is the last in the corresponding VideoOutput type's filters list, meaning - that the returned frame is the one that is going to be presented to the scene - graph without invoking any further filters. - */ - -class QAbstractVideoFilterPrivate -{ -public: - bool active = true; -}; - -/*! - \internal - */ -QVideoFilterRunnable::~QVideoFilterRunnable() = default; - -/*! - Constructs a new QAbstractVideoFilter instance with parent object \a parent. - */ -QAbstractVideoFilter::QAbstractVideoFilter(QObject *parent) : - QObject(parent), - d_ptr(new QAbstractVideoFilterPrivate) -{ -} - -/*! - \internal - */ -QAbstractVideoFilter::~QAbstractVideoFilter() -{ - delete d_ptr; -} - -/*! - \property QAbstractVideoFilter::active - \brief the active status of the filter. - - This is true if the filter is active, false otherwise. - - By default filters are active. When set to \c false, the filter will be - ignored by the VideoOutput type. - */ -bool QAbstractVideoFilter::isActive() const -{ - Q_D(const QAbstractVideoFilter); - return d->active; -} - -void QAbstractVideoFilter::setActive(bool v) -{ - Q_D(QAbstractVideoFilter); - if (d->active != v) { - d->active = v; - emit activeChanged(); - } -} - -/*! - \fn QVideoFilterRunnable *QAbstractVideoFilter::createFilterRunnable() - - Factory function to create a new instance of a QVideoFilterRunnable subclass - corresponding to this filter. - - This function is called on the thread on which the Qt Quick scene graph - performs rendering, with the OpenGL context bound. Ownership of the returned - instance is transferred: the returned instance will live on the render thread - and will be destroyed automatically when necessary. - - Typically, implementations of the function will simply construct a new - QVideoFilterRunnable instance, passing \c this to the constructor as the - filter runnables must know their associated QAbstractVideoFilter instance to - access dynamic properties and optionally emit signals. - */ - -QT_END_NAMESPACE diff --git a/src/multimedia/video/qabstractvideofilter.h b/src/multimedia/video/qabstractvideofilter.h deleted file mode 100644 index 6263f4730..000000000 --- a/src/multimedia/video/qabstractvideofilter.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QABSTRACTVIDEOFILTER_H -#define QABSTRACTVIDEOFILTER_H - -#include <QtCore/qobject.h> -#include <QtMultimedia/qvideoframe.h> -#include <QtMultimedia/qvideosurfaceformat.h> - -QT_BEGIN_NAMESPACE - -class QAbstractVideoFilterPrivate; - -class Q_MULTIMEDIA_EXPORT QVideoFilterRunnable -{ -public: - enum RunFlag { - LastInChain = 0x01 - }; - Q_DECLARE_FLAGS(RunFlags, RunFlag) - - virtual ~QVideoFilterRunnable(); - virtual QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags) = 0; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QVideoFilterRunnable::RunFlags) - -class Q_MULTIMEDIA_EXPORT QAbstractVideoFilter : public QObject -{ - Q_OBJECT - Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) - -public: - explicit QAbstractVideoFilter(QObject *parent = nullptr); - ~QAbstractVideoFilter(); - - bool isActive() const; - void setActive(bool v); - - virtual QVideoFilterRunnable *createFilterRunnable() = 0; - -Q_SIGNALS: - void activeChanged(); - -private: - Q_DECLARE_PRIVATE(QAbstractVideoFilter) - Q_DISABLE_COPY(QAbstractVideoFilter) - - QAbstractVideoFilterPrivate *d_ptr; -}; - -QT_END_NAMESPACE - -#endif // QABSTRACTVIDEOFILTER_H diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri index 6fa650d96..50d1a260b 100644 --- a/src/multimedia/video/video.pri +++ b/src/multimedia/video/video.pri @@ -5,7 +5,6 @@ PUBLIC_HEADERS += \ video/qabstractvideosurface.h \ video/qvideoframe.h \ video/qvideosurfaceformat.h \ - video/qabstractvideofilter.h PRIVATE_HEADERS += \ video/qabstractvideobuffer_p.h \ @@ -23,7 +22,6 @@ SOURCES += \ video/qvideoframe.cpp \ video/qvideooutputorientationhandler.cpp \ video/qvideosurfaceformat.cpp \ - video/qabstractvideofilter.cpp \ video/qvideoframeconversionhelper.cpp \ video/qvideosurfaces.cpp diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp index 10e065ca1..320ad9b86 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp @@ -107,7 +107,7 @@ void QSGVivanteVideoMaterial::setCurrentFrame(const QVideoFrame &frame, QSGVideo { QMutexLocker lock(&mFrameMutex); mCurrentFrame = frame; - mMappable = mMapError == GL_NO_ERROR && !flags.testFlag(QSGVideoNode::FrameFiltered); + mMappable = mMapError == GL_NO_ERROR; #ifdef QT_VIVANTE_VIDEO_DEBUG qDebug() << Q_FUNC_INFO << " new frame: " << frame; diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index 72e04bbe2..1ccea41e1 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -196,10 +196,6 @@ bool QDeclarativeVideoOutput::createBackend() // Since new backend has been created needs to update its geometry. m_geometryDirty = true; - m_backend->clearFilters(); - for (int i = 0; i < m_filters.count(); ++i) - m_backend->appendFilter(m_filters[i]); - return true; } @@ -684,50 +680,6 @@ void QDeclarativeVideoOutput::geometryChange(const QRectF &newGeometry, const QR _q_updateGeometry(); } -/*! - \qmlproperty list<object> QtMultimedia::VideoOutput::filters - - This property holds the list of video filters that are run on the video - frames. The order of the filters in the list matches the order in which - they will be invoked on the video frames. The objects in the list must be - instances of a subclass of QAbstractVideoFilter. - - \sa QAbstractVideoFilter -*/ - -QQmlListProperty<QAbstractVideoFilter> QDeclarativeVideoOutput::filters() -{ - return QQmlListProperty<QAbstractVideoFilter>(this, nullptr, filter_append, filter_count, filter_at, filter_clear); -} - -void QDeclarativeVideoOutput::filter_append(QQmlListProperty<QAbstractVideoFilter> *property, QAbstractVideoFilter *value) -{ - QDeclarativeVideoOutput *self = static_cast<QDeclarativeVideoOutput *>(property->object); - self->m_filters.append(value); - if (self->m_backend) - self->m_backend->appendFilter(value); -} - -qsizetype QDeclarativeVideoOutput::filter_count(QQmlListProperty<QAbstractVideoFilter> *property) -{ - QDeclarativeVideoOutput *self = static_cast<QDeclarativeVideoOutput *>(property->object); - return self->m_filters.count(); -} - -QAbstractVideoFilter *QDeclarativeVideoOutput::filter_at(QQmlListProperty<QAbstractVideoFilter> *property, qsizetype index) -{ - QDeclarativeVideoOutput *self = static_cast<QDeclarativeVideoOutput *>(property->object); - return self->m_filters.at(index); -} - -void QDeclarativeVideoOutput::filter_clear(QQmlListProperty<QAbstractVideoFilter> *property) -{ - QDeclarativeVideoOutput *self = static_cast<QDeclarativeVideoOutput *>(property->object); - self->m_filters.clear(); - if (self->m_backend) - self->m_backend->clearFilters(); -} - void QDeclarativeVideoOutput::_q_invalidateSceneGraph() { if (m_backend) diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h index 93bb8177e..7543cbeac 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h @@ -56,7 +56,6 @@ #include <QtCore/qsharedpointer.h> #include <QtQuick/qquickitem.h> #include <QtCore/qpointer.h> -#include <QtMultimedia/qabstractvideofilter.h> #include <private/qtmultimediaquickdefs_p.h> @@ -65,6 +64,7 @@ QT_BEGIN_NAMESPACE class QDeclarativeVideoBackend; class QVideoOutputOrientationHandler; class QVideoSink; +class QVideoFrame; class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem { @@ -76,7 +76,6 @@ class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem Q_PROPERTY(bool autoOrientation READ autoOrientation WRITE setAutoOrientation NOTIFY autoOrientationChanged REVISION 2) Q_PROPERTY(QRectF sourceRect READ sourceRect NOTIFY sourceRectChanged) 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(QVideoSink* videoSink READ videoSink CONSTANT REVISION 15) Q_ENUMS(FlushMode) @@ -135,8 +134,6 @@ public: }; SourceType sourceType() const; - QQmlListProperty<QAbstractVideoFilter> filters(); - FlushMode flushMode() const { return m_flushMode; } void setFlushMode(FlushMode mode); @@ -164,11 +161,6 @@ private Q_SLOTS: private: bool createBackend(); - static void filter_append(QQmlListProperty<QAbstractVideoFilter> *property, QAbstractVideoFilter *value); - static qsizetype filter_count(QQmlListProperty<QAbstractVideoFilter> *property); - static QAbstractVideoFilter *filter_at(QQmlListProperty<QAbstractVideoFilter> *property, qsizetype index); - static void filter_clear(QQmlListProperty<QAbstractVideoFilter> *property); - QPointer<QObject> m_source; FillMode m_fillMode; @@ -183,7 +175,6 @@ private: QScopedPointer<QDeclarativeVideoBackend> m_backend; - QList<QAbstractVideoFilter *> m_filters; FlushMode m_flushMode = EmptyFrame; }; diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index f62a6c891..17dd61706 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -40,7 +40,6 @@ #include "qdeclarativevideooutput_render_p.h" #include "qdeclarativevideooutput_p.h" -#include <QtMultimedia/qabstractvideofilter.h> #include <QtCore/qobject.h> #include <QtCore/qloggingcategory.h> #include <private/qmediapluginloader_p.h> @@ -66,52 +65,6 @@ QDeclarativeVideoBackend::~QDeclarativeVideoBackend() delete m_sink; } -void QDeclarativeVideoBackend::appendFilter(QAbstractVideoFilter *filter) -{ - QMutexLocker lock(&m_frameMutex); - m_filters.append(Filter(filter)); -} - -void QDeclarativeVideoBackend::clearFilters() -{ - QMutexLocker lock(&m_frameMutex); - scheduleDeleteFilterResources(); - m_filters.clear(); -} - -class FilterRunnableDeleter : public QRunnable -{ -public: - FilterRunnableDeleter(const QList<QVideoFilterRunnable *> &runnables) : m_runnables(runnables) { } - void run() override { - for (QVideoFilterRunnable *runnable : qAsConst(m_runnables)) - delete runnable; - } -private: - QList<QVideoFilterRunnable *> m_runnables; -}; - -void QDeclarativeVideoBackend::scheduleDeleteFilterResources() -{ - if (!q->window()) - return; - - QList<QVideoFilterRunnable *> runnables; - for (int i = 0; i < m_filters.count(); ++i) { - if (m_filters[i].runnable) { - runnables.append(m_filters[i].runnable); - m_filters[i].runnable = nullptr; - } - } - - if (!runnables.isEmpty()) { - // Request the scenegraph to run our cleanup job on the render thread. - // The execution of our QRunnable may happen after the QML tree including the QAbstractVideoFilter instance is - // destroyed on the main thread so no references to it must be used during cleanup. - q->window()->scheduleRenderJob(new FilterRunnableDeleter(runnables), QQuickWindow::BeforeSynchronizingStage); - } -} - void QDeclarativeVideoBackend::releaseResources() { // Called on the gui thread when the window is closed or changed. @@ -121,13 +74,7 @@ void QDeclarativeVideoBackend::releaseResources() void QDeclarativeVideoBackend::invalidateSceneGraph() { // Called on the render thread, e.g. when the context is lost. - QMutexLocker lock(&m_frameMutex); - for (int i = 0; i < m_filters.count(); ++i) { - if (m_filters[i].runnable) { - delete m_filters[i].runnable; - m_filters[i].runnable = nullptr; - } - } +// QMutexLocker lock(&m_frameMutex); } void QDeclarativeVideoBackend::itemChange(QQuickItem::ItemChange change, @@ -210,34 +157,7 @@ QSGNode *QDeclarativeVideoBackend::updatePaintNode(QSGNode *oldNode, QMutexLocker lock(&m_frameMutex); - bool isFrameModified = false; if (m_frameChanged) { - // Run the VideoFilter if there is one. This must be done before potentially changing the videonode below. - if (m_frame.isValid() && !m_filters.isEmpty()) { - for (int i = 0; i < m_filters.count(); ++i) { - QAbstractVideoFilter *filter = m_filters[i].filter; - QVideoFilterRunnable *&runnable = m_filters[i].runnable; - if (filter && filter->isActive()) { - // Create the filter runnable if not yet done. Ownership is taken and is tied to this thread, on which rendering happens. - if (!runnable) - runnable = filter->createFilterRunnable(); - if (!runnable) - continue; - - QVideoFilterRunnable::RunFlags flags; - if (i == m_filters.count() - 1) - flags |= QVideoFilterRunnable::LastInChain; - - QVideoFrame newFrame = runnable->run(&m_frame, m_surfaceFormat, flags); - - if (newFrame.isValid() && newFrame != m_frame) { - isFrameModified = true; - m_frame = newFrame; - } - } - } - } - if (videoNode && videoNode->pixelFormat() != m_frame.pixelFormat()) { qCDebug(qLcVideo) << "updatePaintNode: deleting old video node because frame format changed"; delete videoNode; @@ -269,10 +189,7 @@ QSGNode *QDeclarativeVideoBackend::updatePaintNode(QSGNode *oldNode, videoNode->setTexturedRectGeometry(m_renderedRect, m_sourceTextureRect, qNormalizedOrientation(q->orientation())); if (m_frameChanged) { - QSGVideoNode::FrameFlags flags; - if (isFrameModified) - flags |= QSGVideoNode::FrameFiltered; - videoNode->setCurrentFrame(m_frame, flags); + videoNode->setCurrentFrame(m_frame); if ((q->flushMode() == QDeclarativeVideoOutput::FirstFrame && !m_frameOnFlush.isValid()) || q->flushMode() == QDeclarativeVideoOutput::LastFrame) { diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h index 4fa6e5980..b23b74da2 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h @@ -62,8 +62,6 @@ QT_BEGIN_NAMESPACE class QVideoSink; class QObject; -class QAbstractVideoFilter; -class QVideoFilterRunnable; class QDeclarativeVideoOutput; class QDeclarativeVideoBackend @@ -83,13 +81,10 @@ public: void present(const QVideoFrame &frame); void stop(); - void appendFilter(QAbstractVideoFilter *filter); - void clearFilters(); void releaseResources(); void invalidateSceneGraph(); private: - void scheduleDeleteFilterResources(); QDeclarativeVideoOutput *q; mutable QVideoSink *m_sink = nullptr; @@ -101,14 +96,6 @@ private: QMutex m_frameMutex; QRectF m_renderedRect; // Destination pixel coordinates, clipped QRectF m_sourceTextureRect; // Source texture coordinates - - struct Filter { - Filter() : filter(0), runnable(0) { } - Filter(QAbstractVideoFilter *filter) : filter(filter), runnable(0) { } - QAbstractVideoFilter *filter; - QVideoFilterRunnable *runnable; - }; - QList<Filter> m_filters; }; namespace { diff --git a/src/qtmultimediaquicktools/qsgvideonode_p.cpp b/src/qtmultimediaquicktools/qsgvideonode_p.cpp index 30faf95ef..eb6a31d31 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_p.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_p.cpp @@ -273,7 +273,7 @@ QSGVideoNode::QSGVideoNode(const QVideoSurfaceFormat &format) setMaterial(m_material); } -void QSGVideoNode::setCurrentFrame(const QVideoFrame &frame, FrameFlags) +void QSGVideoNode::setCurrentFrame(const QVideoFrame &frame) { m_material->setCurrentFrame(frame); markDirty(DirtyMaterial); diff --git a/src/qtmultimediaquicktools/qsgvideonode_p.h b/src/qtmultimediaquicktools/qsgvideonode_p.h index 36239cdcd..2422f1388 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_p.h +++ b/src/qtmultimediaquicktools/qsgvideonode_p.h @@ -65,17 +65,12 @@ class QSGVideoMaterial; class QSGVideoNode : public QSGGeometryNode { public: - enum FrameFlag { - FrameFiltered = 0x01 - }; - Q_DECLARE_FLAGS(FrameFlags, FrameFlag) - QSGVideoNode(const QVideoSurfaceFormat &format); QVideoSurfaceFormat::PixelFormat pixelFormat() const { return m_format.pixelFormat(); } - void setCurrentFrame(const QVideoFrame &frame, FrameFlags flags); + void setCurrentFrame(const QVideoFrame &frame); void setTexturedRectGeometry(const QRectF &boundingRect, const QRectF &textureRect, int orientation); @@ -88,8 +83,6 @@ private: QSGVideoMaterial *m_material; }; -Q_DECLARE_OPERATORS_FOR_FLAGS(QSGVideoNode::FrameFlags) - QT_END_NAMESPACE #endif // QSGVIDEONODE_H diff --git a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp index 23ee22d7c..025b11bdf 100644 --- a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp +++ b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp @@ -39,6 +39,7 @@ #include <qobject.h> #include <qvideosurfaceformat.h> +#include <qvideoframe.h> class SurfaceHolder : public QObject { |