Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qffmpeghwaccel_d3d11.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <qvideoframeformat.h>
8
9
10#include <private/qvideotexturehelper_p.h>
11#include <private/qcomptr_p.h>
12#include <rhi/qrhi.h>
13
14#include <qopenglfunctions.h>
15#include <qdebug.h>
16#include <qloggingcategory.h>
17
18#include <libavutil/hwcontext_d3d11va.h>
19
21
22static Q_LOGGING_CATEGORY(qLcMediaFFmpegHWAccel, "qt.multimedia.hwaccel")
23
24namespace QFFmpeg {
25
26class D3D11TextureSet : public TextureSet
27{
28public:
29 D3D11TextureSet(ComPtr<ID3D11Texture2D> &&tex)
30 : m_tex(tex)
31 {}
32
33 qint64 textureHandle(int /*plane*/) override
34 {
35 return qint64(m_tex.Get());
36 }
37
38private:
39 ComPtr<ID3D11Texture2D> m_tex;
40};
41
42
43D3D11TextureConverter::D3D11TextureConverter(QRhi *rhi)
44 : TextureConverterBackend(rhi)
45{
46}
47
48static ComPtr<ID3D11Texture2D> getSharedTextureForDevice(ID3D11Device *dev, ID3D11Texture2D *tex)
49{
50 ComPtr<IDXGIResource> dxgiResource;
51 HRESULT hr = tex->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void **>(dxgiResource.GetAddressOf()));
52 if (FAILED(hr)) {
53 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to obtain resource handle from FFMpeg texture" << hr;
54 return {};
55 }
56 HANDLE shared = nullptr;
57 hr = dxgiResource->GetSharedHandle(&shared);
58 if (FAILED(hr)) {
59 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to obtain shared handle for FFmpeg texture" << hr;
60 return {};
61 }
62
63 ComPtr<ID3D11Texture2D> sharedTex;
64 hr = dev->OpenSharedResource(shared, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(sharedTex.GetAddressOf()));
65 if (FAILED(hr))
66 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to share FFmpeg texture" << hr;
67 return sharedTex;
68}
69
70static ComPtr<ID3D11Texture2D> copyTextureFromArray(ID3D11Device *dev, ID3D11Texture2D *array, int index)
71{
72 D3D11_TEXTURE2D_DESC arrayDesc = {};
73 array->GetDesc(&arrayDesc);
74
75 D3D11_TEXTURE2D_DESC texDesc = {};
76 texDesc.Width = arrayDesc.Width;
77 texDesc.Height = arrayDesc.Height;
78 texDesc.Format = arrayDesc.Format;
79 texDesc.ArraySize = 1;
80 texDesc.MipLevels = 1;
81 texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
82 texDesc.MiscFlags = 0;
83 texDesc.SampleDesc = { 1, 0};
84
85 ComPtr<ID3D11Texture2D> texCopy;
86 HRESULT hr = dev->CreateTexture2D(&texDesc, nullptr, texCopy.GetAddressOf());
87 if (FAILED(hr)) {
88 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to create texture" << hr;
89 return {};
90 }
91
92 ComPtr<ID3D11DeviceContext> ctx;
93 dev->GetImmediateContext(ctx.GetAddressOf());
94 ctx->CopySubresourceRegion(texCopy.Get(), 0, 0, 0, 0, array, index, nullptr);
95
96 return texCopy;
97}
98
99TextureSet *D3D11TextureConverter::getTextures(AVFrame *frame)
100{
101 if (!frame || !frame->hw_frames_ctx || frame->format != AV_PIX_FMT_D3D11)
102 return nullptr;
103
104 auto *fCtx = (AVHWFramesContext *)frame->hw_frames_ctx->data;
105 auto *ctx = fCtx->device_ctx;
106 if (!ctx || ctx->type != AV_HWDEVICE_TYPE_D3D11VA)
107 return nullptr;
108
109 auto nh = static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles());
110 if (!nh)
111 return nullptr;
112
113 auto ffmpegTex = (ID3D11Texture2D *)frame->data[0];
114 int index = (intptr_t)frame->data[1];
115
116 if (rhi->backend() == QRhi::D3D11) {
117 auto dev = reinterpret_cast<ID3D11Device *>(nh->dev);
118 if (!dev)
119 return nullptr;
120 auto sharedTex = getSharedTextureForDevice(dev, ffmpegTex);
121 if (sharedTex) {
122 auto tex = copyTextureFromArray(dev, sharedTex.Get(), index);
123 if (tex) {
124 return new D3D11TextureSet(std::move(tex));
125 }
126 }
127 }
128
129 return nullptr;
130}
131
132void D3D11TextureConverter::SetupDecoderTextures(AVCodecContext *s)
133{
134 int ret = avcodec_get_hw_frames_parameters(s,
135 s->hw_device_ctx,
136 AV_PIX_FMT_D3D11,
137 &s->hw_frames_ctx);
138 if (ret < 0) {
139 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to allocate HW frames context" << ret;
140 return;
141 }
142
143 auto *frames_ctx = (AVHWFramesContext *)s->hw_frames_ctx->data;
144 auto *hwctx = (AVD3D11VAFramesContext *)frames_ctx->hwctx;
145 hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED;
146 hwctx->BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
147 ret = av_hwframe_ctx_init(s->hw_frames_ctx);
148 if (ret < 0) {
149 qCDebug(qLcMediaFFmpegHWAccel) << "Failed to initialize HW frames context" << ret;
150 av_buffer_unref(&s->hw_frames_ctx);
151 }
152}
153
154}
155
\variable QRhiD3D11InitParams::enableDebugLayer
\inmodule QtGui
Definition qrhi.h:1767
Implementation backend() const
Definition qrhi.cpp:8289
@ D3D11
Definition qrhi.h:1773
const QRhiNativeHandles * nativeHandles()
Definition qrhi.cpp:9708
EGLContext ctx
Combined button and popup list for selecting options.
INT_PTR intptr_t
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
return ret
GLuint index
[2]
GLenum array
GLdouble s
[6]
Definition qopenglext.h:235
long long qint64
Definition qtypes.h:55
long HRESULT
QFrame frame
[0]