diff options
author | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-03-28 13:24:28 +0200 |
---|---|---|
committer | Piotr Srebrny <piotr.srebrny@qt.io> | 2022-04-25 11:02:27 +0200 |
commit | aaa9e0eaf2f36aac3ae93026fdfcfb5041fb8a54 (patch) | |
tree | deb7409e59a5437dcd59a29f764995cd2401eaf0 /src/plugins/multimedia/ffmpeg/qffmpeghwaccel_d3d11.cpp | |
parent | e5c2e8c99ef76a6b4493ff562e5398fc3f2dbb69 (diff) | |
download | qtmultimedia-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.cpp | 188 |
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 |