8#include <private/qabstractvideobuffer_p.h>
32 IMFSampleVideoBuffer(ComPtr<IDirect3DDevice9Ex>
device,
41 ~IMFSampleVideoBuffer()
override
44 m_memSurface->UnlockRect();
56 if (FAILED(m_memSurface->GetDesc(&desc)))
60 ComPtr<IMFMediaBuffer>
buffer;
61 HRESULT hr = m_sample->GetBufferByIndex(0,
buffer.GetAddressOf());
65 ComPtr<IDirect3DSurface9> surface;
66 hr = MFGetService(
buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9, (
void **)(surface.GetAddressOf()));
70 if (FAILED(surface->GetDesc(&desc)))
73 if (FAILED(m_device->CreateOffscreenPlainSurface(
desc.Width,
desc.Height,
desc.Format, D3DPOOL_SYSTEMMEM, m_memSurface.GetAddressOf(),
nullptr)))
76 if (FAILED(m_device->GetRenderTargetData(surface.Get(), m_memSurface.Get()))) {
103 m_memSurface->UnlockRect();
107 ComPtr<IDirect3DDevice9Ex> m_device;
108 ComPtr<IMFSample> m_sample;
111 ComPtr<IDirect3DSurface9> m_memSurface;
119 : m_tex(
std::move(tex))
120 , m_d3d11tex(
std::move(d3d11tex))
125 return plane == 0 ? m_tex.get() :
nullptr;
129 std::unique_ptr<QRhiTexture> m_tex;
130 ComPtr<ID3D11Texture2D> m_d3d11tex;
137 HANDLE sharedHandle,
QRhi *rhi)
139 , m_sharedHandle(sharedHandle)
151 auto dev =
reinterpret_cast<ID3D11Device *
>(nh->dev);
155 ComPtr<ID3D11Texture2D> d3d11tex;
156 HRESULT hr = dev->OpenSharedResource(m_sharedHandle, __uuidof(ID3D11Texture2D), (
void**)(d3d11tex.GetAddressOf()));
158 D3D11_TEXTURE2D_DESC desc = {};
159 d3d11tex->GetDesc(&desc);
161 if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM)
163 else if (desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM)
168 std::unique_ptr<QRhiTexture> tex(rhi->
newTexture(
format,
QSize{int(desc.Width), int(desc.Height)}, 1, {}));
169 tex->createFrom({
quint64(d3d11tex.Get()), 0});
170 return std::make_unique<QVideoFrameD3D11Textures>(std::move(tex), std::move(d3d11tex));
173 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to obtain D3D11Texture2D from D3D9Texture2D handle";
179 HANDLE m_sharedHandle =
nullptr;
185 struct InterOpHandles {
192 Q_DISABLE_COPY(QVideoFrameOpenGlTextures);
194 QVideoFrameOpenGlTextures(std::unique_ptr<QRhiTexture> &&tex,
const WglNvDxInterop &wgl, InterOpHandles &handles)
195 : m_tex(
std::move(tex))
200 ~QVideoFrameOpenGlTextures()
override {
202 if (!m_wgl.wglDXUnlockObjectsNV(m_handles.device, 1, &m_handles.texture))
203 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to unlock OpenGL texture";
205 if (!m_wgl.wglDXUnregisterObjectNV(m_handles.device, m_handles.texture))
206 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to unregister OpenGL texture";
210 funcs->glDeleteTextures(1, &m_handles.textureName);
212 qCDebug(qLcEvrD3DPresentEngine) <<
"Could not delete texture, OpenGL context functions missing";
214 if (!m_wgl.wglDXCloseDeviceNV(m_handles.device))
215 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to close D3D-GL device";
218 qCDebug(qLcEvrD3DPresentEngine) <<
"Could not release texture, OpenGL context missing";
222 static std::unique_ptr<QVideoFrameOpenGlTextures>
create(
const WglNvDxInterop &wgl,
QRhi *rhi,
232 InterOpHandles handles = {};
233 handles.device = wgl.wglDXOpenDeviceNV(
device);
234 if (!handles.device) {
235 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to open D3D device";
239 wgl.wglDXSetResourceShareHandleNV(
texture, sharedHandle);
243 funcs->glGenTextures(1, &handles.textureName);
244 handles.texture = wgl.wglDXRegisterObjectNV(handles.device,
texture, handles.textureName,
245 GL_TEXTURE_2D, WglNvDxInterop::WGL_ACCESS_READ_ONLY_NV);
246 if (handles.texture) {
247 if (wgl.wglDXLockObjectsNV(handles.device, 1, &handles.texture)) {
248 D3DSURFACE_DESC
desc;
249 texture->GetLevelDesc(0, &desc);
251 if (
desc.Format == D3DFMT_A8R8G8B8)
253 else if (
desc.Format == D3DFMT_A8B8G8R8)
258 std::unique_ptr<QRhiTexture> tex(rhi->
newTexture(
format,
QSize{int(desc.Width), int(desc.Height)}, 1, {}));
259 tex->createFrom({
quint64(handles.textureName), 0});
260 return std::make_unique<QVideoFrameOpenGlTextures>(std::move(tex), wgl, handles);
263 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed to lock OpenGL texture";
264 wgl.wglDXUnregisterObjectNV(handles.device, handles.texture);
266 qCDebug(qLcEvrD3DPresentEngine) <<
"Could not register D3D9 texture in OpenGL";
269 funcs->glDeleteTextures(1, &handles.textureName);
271 qCDebug(qLcEvrD3DPresentEngine) <<
"Failed generate texture names, OpenGL context functions missing";
278 return plane == 0 ? m_tex.get() :
nullptr;
281 std::unique_ptr<QRhiTexture> m_tex;
282 WglNvDxInterop m_wgl;
283 InterOpHandles m_handles;
286class OpenGlVideoBuffer:
public IMFSampleVideoBuffer
289 OpenGlVideoBuffer(ComPtr<IDirect3DDevice9Ex>
device,
const ComPtr<IMFSample> &sample,
290 const WglNvDxInterop &wglNvDxInterop, HANDLE sharedHandle,
QRhi *rhi)
292 , m_sharedHandle(sharedHandle)
293 , m_wgl(wglNvDxInterop)
296 std::unique_ptr<QVideoFrameTextures> mapTextures(
QRhi *rhi)
override
299 ComPtr<IMFMediaBuffer>
buffer;
300 HRESULT hr = m_sample->GetBufferByIndex(0,
buffer.GetAddressOf());
304 ComPtr<IDirect3DSurface9> surface;
305 hr = MFGetService(
buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9,
306 (
void **)(surface.GetAddressOf()));
310 hr = surface->GetContainer(IID_IDirect3DTexture9, (
void **)m_texture.GetAddressOf());
315 return QVideoFrameOpenGlTextures::create(m_wgl, rhi, m_device.Get(), m_texture.Get(), m_sharedHandle);
319 HANDLE m_sharedHandle =
nullptr;
320 WglNvDxInterop m_wgl;
321 ComPtr<IDirect3DTexture9> m_texture;
326 : m_deviceResetToken(0)
328 ZeroMemory(&m_displayMode,
sizeof(m_displayMode));
355 hr = createD3DDevice();
357 qWarning(
"Failed to create D3D device");
359 qWarning(
"Failed to initialize D3D");
363HRESULT D3DPresentEngine::initializeD3D()
365 HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, m_D3D9.GetAddressOf());
368 hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, m_devices.GetAddressOf());
377 for (
auto i = 0u;
i < D3D9->GetAdapterCount(); ++
i) {
379 D3D9->GetAdapterLUID(
i, &luid);
380 if (luid.LowPart == nh->adapterLuidLow && luid.HighPart == nh->adapterLuidHigh) {
394 fn =
reinterpret_cast<T
>(
ctx->getProcAddress(fName));
395 return fn !=
nullptr;
398static bool readWglNvDxInteropProc(WglNvDxInterop &
f)
404 ctx->makeCurrent(surface.get());
406 auto wglGetExtensionsStringARB =
reinterpret_cast<const char* (WINAPI* )(HDC)
>
407 (
ctx->getProcAddress(
"wglGetExtensionsStringARB"));
408 if (!wglGetExtensionsStringARB) {
409 qCDebug(qLcEvrD3DPresentEngine) <<
"WGL extensions missing (no wglGetExtensionsStringARB function)";
413 HWND hwnd = ::GetShellWindow();
414 auto dc = ::GetDC(hwnd);
416 const char *wglExtString = wglGetExtensionsStringARB(dc);
418 qCDebug(qLcEvrD3DPresentEngine) <<
"WGL extensions missing (wglGetExtensionsStringARB returned null)";
420 bool hasExtension = wglExtString && strstr(wglExtString,
"WGL_NV_DX_interop");
423 qCDebug(qLcEvrD3DPresentEngine) <<
"WGL_NV_DX_interop missing";
427 return getProc(
ctx.get(),
f.wglDXOpenDeviceNV,
"wglDXOpenDeviceNV")
428 && getProc(
ctx.get(),
f.wglDXCloseDeviceNV,
"wglDXCloseDeviceNV")
429 && getProc(
ctx.get(),
f.wglDXSetResourceShareHandleNV,
"wglDXSetResourceShareHandleNV")
430 && getProc(
ctx.get(),
f.wglDXRegisterObjectNV,
"wglDXRegisterObjectNV")
431 && getProc(
ctx.get(),
f.wglDXUnregisterObjectNV,
"wglDXUnregisterObjectNV")
432 && getProc(
ctx.get(),
f.wglDXLockObjectsNV,
"wglDXLockObjectsNV")
433 && getProc(
ctx.get(),
f.wglDXUnlockObjectsNV,
"wglDXUnlockObjectsNV");
439bool hwTextureRenderingEnabled() {
442 static bool isDisableConversionSet =
false;
444 "QT_DISABLE_HW_TEXTURES_CONVERSION", &isDisableConversionSet);
446 return !isDisableConversionSet || !disableHwConversion;
451HRESULT D3DPresentEngine::createD3DDevice()
453 if (!m_D3D9 || !m_devices)
454 return MF_E_NOT_INITIALIZED;
456 m_useTextureRendering =
false;
459 if (hwTextureRenderingEnabled()) {
460 QRhi *rhi = m_sink ? m_sink->
rhi() :
nullptr;
466 m_useTextureRendering = readWglNvDxInteropProc(m_wglNvDxInterop);
469 qCDebug(qLcEvrD3DPresentEngine) <<
"Not supported RHI backend type";
472 qCDebug(qLcEvrD3DPresentEngine) <<
"No RHI associated with this sink";
475 if (!m_useTextureRendering)
476 qCDebug(qLcEvrD3DPresentEngine) <<
"Could not find compatible RHI adapter, zero copy disabled";
480 ZeroMemory(&ddCaps,
sizeof(ddCaps));
482 HRESULT hr = m_D3D9->GetDeviceCaps(adapterID, D3DDEVTYPE_HAL, &ddCaps);
487 if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
488 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
490 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
492 D3DPRESENT_PARAMETERS pp;
493 ZeroMemory(&pp,
sizeof(pp));
495 pp.BackBufferWidth = 1;
496 pp.BackBufferHeight = 1;
497 pp.BackBufferCount = 1;
499 pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
500 pp.BackBufferFormat = D3DFMT_UNKNOWN;
501 pp.hDeviceWindow =
nullptr;
502 pp.Flags = D3DPRESENTFLAG_VIDEO;
503 pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
505 ComPtr<IDirect3DDevice9Ex>
device;
507 hr = m_D3D9->CreateDeviceEx(
511 vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
519 hr = m_D3D9->GetAdapterDisplayMode(adapterID, &m_displayMode);
523 hr = m_devices->ResetDevice(
device.Get(), m_deviceResetToken);
533 return m_device.Get() !=
nullptr;
545 if (
riid == __uuidof(IDirect3DDeviceManager9)) {
547 hr = MF_E_UNSUPPORTED_SERVICE;
549 *
ppv = m_devices.Get();
553 hr = MF_E_UNSUPPORTED_SERVICE;
561 if (!m_D3D9 || !m_device)
567 D3DDEVICE_CREATION_PARAMETERS
params;
569 hr = m_device->GetCreationParameters(&
params);
573 UINT uAdapter =
params.AdapterOrdinal;
576 hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &
mode);
580 hr = m_D3D9->CheckDeviceFormat(uAdapter,
type,
mode.Format,
581 D3DUSAGE_RENDERTARGET,
588 ||
format == D3DFMT_A8R8G8B8
589 ||
format == D3DFMT_X8B8G8R8
590 ||
format == D3DFMT_A8B8G8R8;
592 return ok ? S_OK : D3DERR_NOTAVAILABLE;
596 QList<ComPtr<IMFSample>> &videoSampleQueue,
600 return MF_E_UNEXPECTED;
621 if (d3dFormat == D3DFMT_X8R8G8B8)
622 d3dFormat = D3DFMT_A8R8G8B8;
623 else if (d3dFormat == D3DFMT_X8B8G8R8)
624 d3dFormat = D3DFMT_A8B8G8R8;
626 for (
int i = 0;
i < PRESENTER_BUFFER_COUNT;
i++) {
629 ComPtr<IDirect3DTexture9>
texture;
630 HANDLE sharedHandle =
nullptr;
631 hr = m_device->CreateTexture(
width,
height, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)d3dFormat, D3DPOOL_DEFAULT,
texture.GetAddressOf(), &sharedHandle);
635 ComPtr<IDirect3DSurface9> surface;
636 hr =
texture->GetSurfaceLevel(0, surface.GetAddressOf());
640 ComPtr<IMFSample> videoSample;
641 hr = MFCreateVideoSampleFromSurface(surface.Get(), videoSample.GetAddressOf());
645 m_sampleTextureHandle[
i] = {videoSample.Get(), sharedHandle};
646 videoSampleQueue.append(videoSample);
663 HANDLE sharedHandle =
nullptr;
664 for (
const auto &
p : m_sampleTextureHandle)
665 if (
p.first == sample.Get())
666 sharedHandle =
p.second;
669 QRhi *rhi = m_sink ? m_sink->
rhi() :
nullptr;
670 if (m_useTextureRendering && sharedHandle && rhi) {
675 vb =
new OpenGlVideoBuffer(m_device, sample, m_wglNvDxInterop, sharedHandle, rhi);
687 auto hr = sample->GetSampleTime(&
startTime);
691 LONGLONG duration = -1;
692 if (SUCCEEDED(sample->GetSampleDuration(&duration)))
IOBluetoothDevice * device
std::unique_ptr< QVideoFrameTextures > mapTextures(QRhi *rhi) override
D3D11TextureVideoBuffer(ComPtr< IDirect3DDevice9Ex > device, const ComPtr< IMFSample > &sample, HANDLE sharedHandle, QRhi *rhi)
void setSink(QVideoSink *sink)
HRESULT createVideoSamples(IMFMediaType *format, QList< ComPtr< IMFSample > > &videoSampleQueue, QSize frameSize)
HRESULT getService(REFGUID guidService, REFIID riid, void **ppv)
virtual ~D3DPresentEngine()
friend class IMFSampleVideoBuffer
D3DPresentEngine(QVideoSink *sink)
HRESULT checkFormat(D3DFORMAT format)
QVideoFrame makeVideoFrame(const ComPtr< IMFSample > &sample)
The QAbstractVideoBuffer class is an abstraction for video data. \inmodule QtMultimedia.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
\variable QRhiD3D11InitParams::enableDebugLayer
Format
Specifies the texture format.
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Implementation backend() const
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
const QRhiNativeHandles * nativeHandles()
QVideoFrameD3D11Textures(std::unique_ptr< QRhiTexture > &&tex, ComPtr< ID3D11Texture2D > &&d3d11tex)
QRhiTexture * texture(uint plane) const override
The QVideoFrame class represents a frame of video data.
MapMode
Enumerates how a video buffer's data is mapped to system memory.
HandleType
Identifies the type of a video buffers handle.
The QVideoSink class represents a generic sink for video data.
QRhi * rhi() const
Returns the QRhi instance being used to create texture data in the video frames.
static VulkanServerBufferGlFunctions * funcs
QMap< QString, QString > map
[6]
static bool findD3D11AdapterID(QRhi &rhi, IDirect3D9Ex *D3D9, UINT &adapterID)
QVideoFrameFormat::PixelFormat qt_evr_pixelFormatFromD3DFormat(DWORD format)
QT_BEGIN_NAMESPACE HRESULT qt_evr_getFourCC(IMFMediaType *type, DWORD *fourCC)
Combined button and popup list for selecting options.
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLint GLsizei GLsizei height
GLint GLsizei GLsizei GLenum format
GLsizei GLenum GLboolean sink
static QAbstractVideoBuffer::MapData mapData(const camera_frame_nv12_t &frame, unsigned char *baseAddress)
static constexpr QSize frameSize(const T &frame)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned long long quint64
IUIViewSettingsInterop __RPC__in REFIID riid
IUIViewSettingsInterop __RPC__in REFIID __RPC__deref_out_opt void ** ppv