File indexing completed on 2025-01-19 03:57:04
0001 /********************************************************* 0002 * Copyright (C) 2020, Val Doroshchuk <valbok@gmail.com> * 0003 * * 0004 * This file is part of QtAVPlayer. * 0005 * Free Qt Media Player based on FFmpeg. * 0006 *********************************************************/ 0007 0008 #include "qavhwdevice_d3d11_p.h" 0009 #include "qavvideobuffer_gpu_p.h" 0010 #include <d3d11.h> 0011 0012 #ifdef QT_AVPLAYER_MULTIMEDIA 0013 0014 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) 0015 #include <private/qrhi_p.h> 0016 #include <private/qrhid3d11_p.h> 0017 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 2) 0018 #include <private/qcomptr_p.h> 0019 #else 0020 #include <private/qwindowsiupointer_p.h> 0021 template <class T> 0022 using ComPtr = QWindowsIUPointer<T>; 0023 #endif 0024 #include <system_error> 0025 #endif 0026 0027 #endif // QT_AVPLAYER_MULTIMEDIA 0028 0029 extern "C" { 0030 #include <libavcodec/avcodec.h> 0031 #include <libavcodec/d3d11va.h> 0032 #include <libavutil/hwcontext_d3d11va.h> 0033 } 0034 0035 QT_BEGIN_NAMESPACE 0036 0037 void QAVHWDevice_D3D11::init(AVCodecContext *avctx) 0038 { 0039 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) 0040 int ret = avcodec_get_hw_frames_parameters(avctx, 0041 avctx->hw_device_ctx, 0042 AV_PIX_FMT_D3D11, 0043 &avctx->hw_frames_ctx); 0044 0045 if (ret < 0) { 0046 qWarning() << "Failed to allocate HW frames context:" << ret; 0047 return; 0048 } 0049 0050 auto frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; 0051 auto hwctx = (AVD3D11VAFramesContext *)frames_ctx->hwctx; 0052 hwctx->MiscFlags = D3D11_RESOURCE_MISC_SHARED; 0053 hwctx->BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE; 0054 ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); 0055 if (ret < 0) { 0056 qWarning() << "Failed to initialize HW frames context:" << ret; 0057 av_buffer_unref(&avctx->hw_frames_ctx); 0058 } 0059 #else 0060 Q_UNUSED(avctx); 0061 #endif 0062 } 0063 0064 AVPixelFormat QAVHWDevice_D3D11::format() const 0065 { 0066 return AV_PIX_FMT_D3D11; 0067 } 0068 0069 AVHWDeviceType QAVHWDevice_D3D11::type() const 0070 { 0071 return AV_HWDEVICE_TYPE_D3D11VA; 0072 } 0073 0074 #ifdef QT_AVPLAYER_MULTIMEDIA 0075 0076 #if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) 0077 0078 template <class T> 0079 static T **address(ComPtr<T> &ptr) 0080 { 0081 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 2) 0082 return ptr.GetAddressOf(); 0083 #else 0084 return ptr.address(); 0085 #endif 0086 } 0087 0088 template <class T> 0089 static T *get(const ComPtr<T> &ptr) 0090 { 0091 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 2) 0092 return ptr.Get(); 0093 #else 0094 return ptr.get(); 0095 #endif 0096 } 0097 0098 static ComPtr<ID3D11Texture2D> shareTexture(ID3D11Device *dev, ID3D11Texture2D *tex) 0099 { 0100 ComPtr<IDXGIResource> dxgiResource; 0101 HRESULT hr = tex->QueryInterface(__uuidof(IDXGIResource), reinterpret_cast<void **>(address(dxgiResource))); 0102 if (FAILED(hr)) { 0103 qWarning() << "Failed to obtain resource handle from FFmpeg texture:" << hr << std::system_category().message(hr); 0104 return {}; 0105 } 0106 0107 HANDLE shared = nullptr; 0108 hr = dxgiResource->GetSharedHandle(&shared); 0109 if (FAILED(hr)) { 0110 qWarning() << "Failed to obtain shared handle for FFmpeg texture:" << hr << std::system_category().message(hr); 0111 return {}; 0112 } 0113 0114 ComPtr<ID3D11Texture2D> sharedTex; 0115 hr = dev->OpenSharedResource(shared, __uuidof(ID3D11Texture2D), reinterpret_cast<void **>(address(sharedTex))); 0116 if (FAILED(hr)) 0117 qWarning() << "Failed to share FFmpeg texture:" << hr << std::system_category().message(hr); 0118 return sharedTex; 0119 } 0120 0121 static ComPtr<ID3D11Texture2D> copyTexture(ID3D11Device *dev, ID3D11Texture2D *from, int index) 0122 { 0123 D3D11_TEXTURE2D_DESC fromDesc = {}; 0124 from->GetDesc(&fromDesc); 0125 0126 D3D11_TEXTURE2D_DESC toDesc = {}; 0127 toDesc.Width = fromDesc.Width; 0128 toDesc.Height = fromDesc.Height; 0129 toDesc.Format = fromDesc.Format; 0130 toDesc.ArraySize = 1; 0131 toDesc.MipLevels = 1; 0132 toDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 0133 toDesc.MiscFlags = 0; 0134 toDesc.SampleDesc = { 1, 0 }; 0135 0136 ComPtr<ID3D11Texture2D> copy; 0137 HRESULT hr = dev->CreateTexture2D(&toDesc, nullptr, address(copy)); 0138 if (FAILED(hr)) { 0139 qWarning() << "Failed to create texture:" << hr << std::system_category().message(hr); 0140 return {}; 0141 } 0142 0143 ComPtr<ID3D11DeviceContext> ctx; 0144 dev->GetImmediateContext(address(ctx)); 0145 ctx->CopySubresourceRegion(get(copy), 0, 0, 0, 0, from, index, nullptr); 0146 return copy; 0147 } 0148 0149 class VideoBuffer_D3D11: public QAVVideoBuffer_GPU 0150 { 0151 public: 0152 VideoBuffer_D3D11(const QAVVideoFrame &frame) 0153 : QAVVideoBuffer_GPU(frame) 0154 { 0155 } 0156 0157 QAVVideoFrame::HandleType handleType() const override 0158 { 0159 return QAVVideoFrame::D3D11Texture2DHandle; 0160 } 0161 0162 QVariant handle(QRhi *rhi) const override 0163 { 0164 if (!rhi || rhi->backend() != QRhi::D3D11) 0165 return {}; 0166 0167 if (!m_texture) { 0168 if (frame().format() != AV_PIX_FMT_NV12) { 0169 qWarning() << "Only NV12 is supported"; 0170 return {}; 0171 } 0172 auto av_frame = frame().frame(); 0173 auto texture = (ID3D11Texture2D *)(uintptr_t)av_frame->data[0]; 0174 auto texture_index = (intptr_t)av_frame->data[1]; 0175 if (!texture) { 0176 qWarning() << "No texture in the frame" << frame().pts(); 0177 return {}; 0178 } 0179 auto nh = static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles()); 0180 if (!nh) { 0181 qWarning() << "No QRhiD3D11NativeHandles"; 0182 return {}; 0183 } 0184 0185 auto dev = reinterpret_cast<ID3D11Device *>(nh->dev); 0186 if (!dev) { 0187 qWarning() << "No ID3D11Device device"; 0188 return {}; 0189 } 0190 auto shared = shareTexture(dev, texture); 0191 if (shared) 0192 const_cast<VideoBuffer_D3D11*>(this)->m_texture = copyTexture(dev, get(shared), texture_index); 0193 } 0194 0195 QList<quint64> textures = {quint64(get(m_texture)), quint64(get(m_texture))}; 0196 return QVariant::fromValue(textures); 0197 } 0198 0199 ComPtr<ID3D11Texture2D> m_texture; 0200 }; 0201 0202 QAVVideoBuffer *QAVHWDevice_D3D11::videoBuffer(const QAVVideoFrame &frame) const 0203 { 0204 return new VideoBuffer_D3D11(frame); 0205 } 0206 0207 #else // QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) 0208 0209 QAVVideoBuffer *QAVHWDevice_D3D11::videoBuffer(const QAVVideoFrame &frame) const 0210 { 0211 return new QAVVideoBuffer_GPU(frame); 0212 } 0213 0214 #endif 0215 0216 #else // QT_AVPLAYER_MULTIMEDIA 0217 0218 QAVVideoBuffer *QAVHWDevice_D3D11::videoBuffer(const QAVVideoFrame &frame) const 0219 { 0220 return new QAVVideoBuffer_GPU(frame); 0221 } 0222 0223 #endif // QT_AVPLAYER_MULTIMEDIA 0224 0225 QT_END_NAMESPACE