summaryrefslogtreecommitdiffstats
path: root/src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp')
-rw-r--r--src/plugins/winrt/qwinrtabstractvideorenderercontrol.cpp489
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