diff options
Diffstat (limited to 'src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp')
-rw-r--r-- | src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp | 489 |
1 files changed, 0 insertions, 489 deletions
diff --git a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp b/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp deleted file mode 100644 index 654d0e605..000000000 --- a/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp +++ /dev/null @@ -1,489 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies). -** 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 "qwinrtabstractvideorenderercontrol.h" - -#include <QtCore/qfunctions_winrt.h> -#include <QtCore/QGlobalStatic> -#include <QtCore/QLoggingCategory> -#include <QtCore/QMetaMethod> -#include <QtCore/QMutexLocker> -#include <QtCore/QPointer> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLTexture> -#include <QtMultimedia/QAbstractVideoBuffer> -#include <QtMultimedia/QAbstractVideoSurface> -#include <QtMultimedia/QVideoSurfaceFormat> - -#define EGL_EGLEXT_PROTOTYPES -#include <EGL/egl.h> -#include <EGL/eglext.h> - -#include <d3d11.h> -#include <mfapi.h> -#include <wrl.h> - -using namespace Microsoft::WRL; - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcMMVideoRender, "qt.mm.videorender") - -#define BREAK_IF_FAILED(msg) RETURN_IF_FAILED(msg, break) -#define CONTINUE_IF_FAILED(msg) RETURN_IF_FAILED(msg, continue) - -// Global D3D device to be shared between video surfaces -struct QWinRTVideoRendererControlGlobal -{ - QWinRTVideoRendererControlGlobal() - { - qCDebug(lcMMVideoRender) << __FUNCTION__; - HRESULT hr; - - D3D_FEATURE_LEVEL featureLevels[] = - { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1 - }; - - UINT flags = D3D11_CREATE_DEVICE_VIDEO_SUPPORT; -#ifdef _DEBUG - flags |= D3D11_CREATE_DEVICE_DEBUG; -#endif - hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, - featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, - &device, &featureLevel, &context); -#ifdef _DEBUG - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to create D3D device with device debug flag"); - hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, D3D11_CREATE_DEVICE_VIDEO_SUPPORT, - featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, - &device, &featureLevel, &context); - } -#endif - if (FAILED(hr)) - qErrnoWarning(hr, "Failed to create D3D device"); - - if (!device || FAILED(hr)) { - hr = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, flags, - featureLevels, ARRAYSIZE(featureLevels), D3D11_SDK_VERSION, - &device, &featureLevel, &context); - if (FAILED(hr)) { - qErrnoWarning(hr, "Failed to create software D3D device"); - return; - } - } - - ComPtr<ID3D10Multithread> multithread; - hr = device.As(&multithread); - Q_ASSERT_SUCCEEDED(hr); - hr = multithread->SetMultithreadProtected(true); - Q_ASSERT_SUCCEEDED(hr); - - ComPtr<IDXGIDevice> dxgiDevice; - hr = device.As(&dxgiDevice); - Q_ASSERT_SUCCEEDED(hr); - ComPtr<IDXGIAdapter> adapter; - hr = dxgiDevice->GetAdapter(&adapter); - Q_ASSERT_SUCCEEDED(hr); - hr = adapter->EnumOutputs(0, &output); - Q_ASSERT_SUCCEEDED(hr); - } - - ComPtr<ID3D11Device> device; - ComPtr<ID3D11DeviceContext> context; - D3D_FEATURE_LEVEL featureLevel; - ComPtr<IDXGIOutput> output; -}; -Q_GLOBAL_STATIC(QWinRTVideoRendererControlGlobal, g) - -class QWinRTVideoBuffer : public QAbstractVideoBuffer, public QOpenGLTexture -{ -public: - QWinRTVideoBuffer(const QSize &size, TextureFormat format) - : QAbstractVideoBuffer(QAbstractVideoBuffer::GLTextureHandle) - , QOpenGLTexture(QOpenGLTexture::Target2D) - { - setSize(size.width(), size.height()); - setFormat(format); - create(); - } - - MapMode mapMode() const override - { - return NotMapped; - } - - uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) override - { - Q_UNUSED(mode); - Q_UNUSED(numBytes); - Q_UNUSED(bytesPerLine); - return nullptr; - } - - void unmap() override - { - } - - QVariant handle() const override - { - return QVariant::fromValue(textureId()); - } -}; - -enum DirtyState { - NotDirty, // All resources have been created - TextureDirty, // The shared D3D texture needs to be recreated - SurfaceDirty // The shared EGL surface needs to be recreated -}; - -class QWinRTAbstractVideoRendererControlPrivate -{ -public: - QPointer<QAbstractVideoSurface> surface; - QVideoSurfaceFormat format; - - DirtyState dirtyState; - - HANDLE shareHandle; - ComPtr<ID3D11Texture2D> texture; - - EGLDisplay eglDisplay; - EGLConfig eglConfig; - EGLSurface eglSurface; - - QVideoFrame presentFrame; - - QThread renderThread; - bool active; - QWinRTAbstractVideoRendererControl::BlitMode blitMode; - QMutex mutex; -}; - -ID3D11Device *QWinRTAbstractVideoRendererControl::d3dDevice() -{ - return g->device.Get(); -} - -// This is required so that subclasses can stop the render thread before deletion -void QWinRTAbstractVideoRendererControl::shutdown() -{ - qCDebug(lcMMVideoRender) << __FUNCTION__; - Q_D(QWinRTAbstractVideoRendererControl); - if (d->renderThread.isRunning()) { - d->renderThread.requestInterruption(); - d->renderThread.wait(); - } -} - -QWinRTAbstractVideoRendererControl::QWinRTAbstractVideoRendererControl(const QSize &size, QObject *parent) - : QVideoRendererControl(parent), d_ptr(new QWinRTAbstractVideoRendererControlPrivate) -{ - qCDebug(lcMMVideoRender) << __FUNCTION__; - Q_D(QWinRTAbstractVideoRendererControl); - - d->format = QVideoSurfaceFormat(size, QVideoFrame::Format_BGRA32, - QAbstractVideoBuffer::GLTextureHandle); - d->dirtyState = TextureDirty; - d->shareHandle = nullptr; - d->eglDisplay = EGL_NO_DISPLAY; - d->eglConfig = nullptr; - d->eglSurface = EGL_NO_SURFACE; - d->active = false; - d->blitMode = DirectVideo; - - connect(&d->renderThread, &QThread::started, - this, &QWinRTAbstractVideoRendererControl::syncAndRender, - Qt::DirectConnection); -} - -QWinRTAbstractVideoRendererControl::~QWinRTAbstractVideoRendererControl() -{ - qCDebug(lcMMVideoRender) << __FUNCTION__; - Q_D(QWinRTAbstractVideoRendererControl); - QMutexLocker locker(&d->mutex); - shutdown(); - locker.unlock(); - eglDestroySurface(d->eglDisplay, d->eglSurface); -} - -QAbstractVideoSurface *QWinRTAbstractVideoRendererControl::surface() const -{ - Q_D(const QWinRTAbstractVideoRendererControl); - return d->surface; -} - -void QWinRTAbstractVideoRendererControl::setSurface(QAbstractVideoSurface *surface) -{ - Q_D(QWinRTAbstractVideoRendererControl); - d->surface = surface; -} - -void QWinRTAbstractVideoRendererControl::syncAndRender() -{ - qCDebug(lcMMVideoRender) << __FUNCTION__; - Q_D(QWinRTAbstractVideoRendererControl); - - QThread *currentThread = QThread::currentThread(); - const QMetaMethod present = staticMetaObject.method(staticMetaObject.indexOfMethod("present()")); - forever { - if (currentThread->isInterruptionRequested()) - break; - { - QMutexLocker lock(&d->mutex); - HRESULT hr; - if (d->dirtyState == TextureDirty) { - CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, d->format.frameWidth(), d->format.frameHeight(), 1, 1); - desc.BindFlags |= D3D11_BIND_RENDER_TARGET; - desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED; - hr = g->device->CreateTexture2D(&desc, nullptr, d->texture.ReleaseAndGetAddressOf()); - BREAK_IF_FAILED("Failed to get create video texture"); - ComPtr<IDXGIResource> resource; - hr = d->texture.As(&resource); - BREAK_IF_FAILED("Failed to cast texture to resource"); - hr = resource->GetSharedHandle(&d->shareHandle); - BREAK_IF_FAILED("Failed to get texture share handle"); - d->dirtyState = SurfaceDirty; - } - - hr = g->output->WaitForVBlank(); - CONTINUE_IF_FAILED("Failed to wait for vertical blank"); - - bool success = false; - switch (d->blitMode) { - case DirectVideo: - success = render(d->texture.Get()); - break; - case MediaFoundation: - success = dequeueFrame(&d->presentFrame); - break; - default: - success = false; - } - - if (!success) - continue; - - // Queue to the control's thread for presentation - present.invoke(this, Qt::QueuedConnection); - currentThread->eventDispatcher()->processEvents(QEventLoop::AllEvents); - } - } - - // All done, exit render loop - currentThread->quit(); -} - -QSize QWinRTAbstractVideoRendererControl::size() const -{ - Q_D(const QWinRTAbstractVideoRendererControl); - return d->format.frameSize(); -} - -void QWinRTAbstractVideoRendererControl::setSize(const QSize &size) -{ - Q_D(QWinRTAbstractVideoRendererControl); - - if (d->format.frameSize() == size) - return; - - d->format.setFrameSize(size); - d->dirtyState = TextureDirty; -} - -void QWinRTAbstractVideoRendererControl::setScanLineDirection(QVideoSurfaceFormat::Direction scanLineDirection) -{ - Q_D(QWinRTAbstractVideoRendererControl); - - if (d->format.scanLineDirection() == scanLineDirection) - return; - - d->format.setScanLineDirection(scanLineDirection); -} - -void QWinRTAbstractVideoRendererControl::setActive(bool active) -{ - qCDebug(lcMMVideoRender) << __FUNCTION__ << active; - Q_D(QWinRTAbstractVideoRendererControl); - - if (d->active == active) - return; - - d->active = active; - if (d->active) { - if (!d->surface) - return; - - // This only happens for quick restart scenarios, for instance - // when switching cameras. - if (d->renderThread.isRunning() && d->renderThread.isInterruptionRequested()) { - QMutexLocker lock(&d->mutex); - d->renderThread.wait(); - } - - if (!d->surface->isActive()) - d->surface->start(d->format); - - d->renderThread.start(); - return; - } - - d->renderThread.requestInterruption(); - - if (d->surface && d->surface->isActive()) - d->surface->stop(); -} - -QWinRTAbstractVideoRendererControl::BlitMode QWinRTAbstractVideoRendererControl::blitMode() const -{ - Q_D(const QWinRTAbstractVideoRendererControl); - return d->blitMode; -} - -void QWinRTAbstractVideoRendererControl::setBlitMode(QWinRTAbstractVideoRendererControl::BlitMode mode) -{ - Q_D(QWinRTAbstractVideoRendererControl); - QMutexLocker lock(&d->mutex); - - if (d->blitMode == mode) - return; - - d->blitMode = mode; - d->dirtyState = d->blitMode == MediaFoundation ? NotDirty : TextureDirty; - - if (d->blitMode == DirectVideo) - return; - - if (d->texture) { - d->texture.Reset(); - d->shareHandle = nullptr; - } - - if (d->eglSurface) { - eglDestroySurface(d->eglDisplay, d->eglSurface); - d->eglSurface = EGL_NO_SURFACE; - } -} - -bool QWinRTAbstractVideoRendererControl::dequeueFrame(QVideoFrame *frame) -{ - Q_UNUSED(frame) - return false; -} - -void QWinRTAbstractVideoRendererControl::textureToFrame() -{ - Q_D(QWinRTAbstractVideoRendererControl); - - if (d->dirtyState == SurfaceDirty) { - if (!QOpenGLContext::currentContext()) { - qWarning("A valid OpenGL context is required for binding the video texture."); - return; - } - - if (d->eglDisplay == EGL_NO_DISPLAY) - d->eglDisplay = eglGetCurrentDisplay(); - - if (d->eglDisplay == EGL_NO_DISPLAY) { - qWarning("Failed to get the current EGL display for video presentation: 0x%x", eglGetError()); - return; - } - - EGLint configAttributes[] = { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE, - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_NONE - }; - EGLint configCount; - if (!eglChooseConfig(d->eglDisplay, configAttributes, &d->eglConfig, 1, &configCount)) { - qWarning("Failed to create the texture EGL configuration for video presentation: 0x%x", eglGetError()); - return; - } - - if (d->eglSurface != EGL_NO_SURFACE) - eglDestroySurface(d->eglDisplay, d->eglSurface); - - EGLint bufferAttributes[] = { - EGL_WIDTH, d->format.frameWidth(), - EGL_HEIGHT, d->format.frameHeight(), - EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, - EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, - EGL_NONE - }; - d->eglSurface = eglCreatePbufferFromClientBuffer(d->eglDisplay, - EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, - d->shareHandle, d->eglConfig, bufferAttributes); - if (d->eglSurface == EGL_NO_SURFACE) { - qWarning("Failed to create the EGL configuration for video presentation: 0x%x", eglGetError()); - return; - } - - QWinRTVideoBuffer *videoBuffer = new QWinRTVideoBuffer(d->format.frameSize(), QOpenGLTexture::RGBAFormat); - d->presentFrame = QVideoFrame(videoBuffer, d->format.frameSize(), d->format.pixelFormat()); - - // bind the pbuffer surface to the texture - videoBuffer->bind(); - eglBindTexImage(d->eglDisplay, d->eglSurface, EGL_BACK_BUFFER); - static_cast<QOpenGLTexture *>(videoBuffer)->release(); - - d->dirtyState = NotDirty; - } -} - -void QWinRTAbstractVideoRendererControl::present() -{ - Q_D(QWinRTAbstractVideoRendererControl); - if (d->blitMode == DirectVideo) - textureToFrame(); - - // Present the frame - d->surface->present(d->presentFrame); -} - -QT_END_NAMESPACE |