summaryrefslogtreecommitdiff
path: root/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
diff options
context:
space:
mode:
authorPiotr Srebrny <piotr.srebrny@qt.io>2022-03-28 13:24:28 +0200
committerPiotr Srebrny <piotr.srebrny@qt.io>2022-04-25 11:02:27 +0200
commitaaa9e0eaf2f36aac3ae93026fdfcfb5041fb8a54 (patch)
treedeb7409e59a5437dcd59a29f764995cd2401eaf0 /src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
parente5c2e8c99ef76a6b4493ff562e5398fc3f2dbb69 (diff)
downloadqtmultimedia-aaa9e0eaf2f36aac3ae93026fdfcfb5041fb8a54.tar.gz
Enable HW acceleration on Windows with D3D11 textures
This patch enables HW accelerated decoding of video with D3D11. The decoded frames arrive as a texture array with an index into the array pointing to where the decoded frame is located. This texture is shared with the D3D11 display device. Two elements are missing: 1) D3D11 rendered texture sharing with OpenGL display QRhi 2) Seting up the correct D3D11 adapter for texture decoding to avoid copying texture between decoding adapter and displaying adapter Change-Id: I18629a7d18471607d9920cf23cf9d81adcec1e7c Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp')
-rw-r--r--src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
new file mode 100644
index 000000000..cc7f3d540
--- /dev/null
+++ b/src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 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 "qffmpeghwaccel_d3d11_p.h"
+
+#include <qvideoframeformat.h>
+#include "qffmpegvideobuffer_p.h"
+
+
+#include <private/qvideotexturehelper_p.h>
+#include <private/qrhi_p.h>
+#include <private/qrhid3d11_p.h>
+
+#include <qopenglfunctions.h>
+#include <qdebug.h>
+#include <qloggingcategory.h>
+
+#include <libavutil/hwcontext_d3d11va.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcMediaFFmpegHWAccel, "qt.multimedia.hwaccel")
+
+namespace QFFmpeg {
+
+class D3D11TextureSet : public TextureSet
+{
+public:
+ D3D11TextureSet(QRhi *rhi, QVideoFrameFormat::PixelFormat format, ID3D11Texture2D *tex, int index)
+ : m_rhi(rhi)
+ , m_format(format)
+ , m_tex(tex)
+ , m_index(index)
+ {}
+
+ ~D3D11TextureSet() override {
+ if (m_tex)
+ m_tex->Release();
+ }
+
+ std::unique_ptr<QRhiTexture> texture(int plane) override {
+ auto desc = QVideoTextureHelper::textureDescription(m_format);
+ if (!m_tex || !m_rhi || !desc || plane >= desc->nplanes)
+ return {};
+
+ D3D11_TEXTURE2D_DESC d3d11desc = {};
+ m_tex->GetDesc(&d3d11desc);
+
+ QSize planeSize(desc->widthForPlane(int(d3d11desc.Width), plane),
+ desc->heightForPlane(int(d3d11desc.Height), plane));
+
+ std::unique_ptr<QRhiTexture> tex(m_rhi->newTextureArray(desc->textureFormat[plane],
+ int(d3d11desc.ArraySize),
+ planeSize, 1, {}));
+ if (tex) {
+ tex->setArrayRange(m_index, 1);
+ if (!tex->createFrom({quint64(m_tex), 0}))
+ tex.reset();
+ }
+ return tex;
+ }
+
+private:
+ QVideoFrameFormat::PixelFormat m_format;
+ QRhi *m_rhi = nullptr;
+ ID3D11Texture2D *m_tex = nullptr;
+ int m_index = 0;
+};
+
+
+D3D11TextureConverter::D3D11TextureConverter(QRhi *rhi)
+ : TextureConverterBackend(rhi)
+{
+}
+
+TextureSet *D3D11TextureConverter::getTextures(AVFrame *frame)
+{
+ if (!frame || !frame->hw_frames_ctx || frame->format != AV_PIX_FMT_D3D11)
+ return nullptr;
+
+ auto *fCtx = (AVHWFramesContext *)frame->hw_frames_ctx->data;
+ auto *ctx = fCtx->device_ctx;
+ if (!ctx || ctx->type != AV_HWDEVICE_TYPE_D3D11VA)
+ return nullptr;
+
+ auto nh = static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles());
+ if (!nh)
+ return nullptr;
+
+ auto dev = reinterpret_cast<ID3D11Device *>(nh->dev);
+ if (!dev)
+ return nullptr;
+
+ auto ffmpegTex = (ID3D11Texture2D *)frame->data[0];
+ int index = (intptr_t)frame->data[1];
+
+ IDXGIResource *dxgiResource = nullptr;
+ HRESULT hr = ffmpegTex->QueryInterface(__uuidof(IDXGIResource), (void **)&dxgiResource);
+ if (FAILED(hr)) {
+ qCDebug(qLcMediaFFmpegHWAccel) << "Failed to obtain resource handle from FFMpeg texture" << hr;
+ return nullptr;
+ }
+ HANDLE shared = nullptr;
+ hr = dxgiResource->GetSharedHandle(&shared);
+ dxgiResource->Release();
+ if (FAILED(hr)) {
+ qCDebug(qLcMediaFFmpegHWAccel) << "Failed to obtain shared handle for FFmpeg texture" << hr;
+ return nullptr;
+ }
+
+ if (rhi->backend() == QRhi::D3D11) {
+ ID3D11Texture2D *sharedTex = nullptr;
+ hr = dev->OpenSharedResource(shared, __uuidof(ID3D11Texture2D), (void **)(&sharedTex));
+ if (FAILED(hr)) {
+ qCDebug(qLcMediaFFmpegHWAccel) << "Failed to share FFmpeg texture" << hr;
+ return nullptr;
+ }
+
+ QVideoFrameFormat::PixelFormat format = QFFmpegVideoBuffer::toQtPixelFormat(AVPixelFormat(fCtx->sw_format));
+ return new D3D11TextureSet(rhi, format, sharedTex, index);
+ } else if (rhi->backend() == QRhi::OpenGLES2) {
+
+ }
+
+ return nullptr;
+}
+
+void D3D11TextureConverter::SetupDecoderTextures(AVCodecContext *s)
+{
+ int ret = avcodec_get_hw_frames_parameters(s,
+ s->hw_device_ctx,
+ AV_PIX_FMT_D3D11,
+ &s->hw_frames_ctx);
+ if (ret < 0) {
+ qCDebug(qLcMediaFFmpegHWAccel) << "Failed to allocate HW frames context" << ret;
+ return;
+ }
+
+ auto *frames_ctx = (AVHWFramesContext *)s->hw_frames_ctx->data;
+ auto *hwctx = (AVD3D11VAFramesContext *)frames_ctx->hwctx;
+ hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+ hwctx->BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
+ ret = av_hwframe_ctx_init(s->hw_frames_ctx);
+ if (ret < 0) {
+ qCDebug(qLcMediaFFmpegHWAccel) << "Failed to initialize HW frames context" << ret;
+ av_buffer_unref(&s->hw_frames_ctx);
+ }
+}
+
+}
+
+QT_END_NAMESPACE