Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
evrd3dpresentengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "evrhelpers_p.h"
7
8#include <private/qhwvideobuffer_p.h>
9#include <private/qvideoframe_p.h>
10#include <qvideoframe.h>
11#include <QDebug>
12#include <qthread.h>
13#include <qvideosink.h>
14#include <qloggingcategory.h>
15
16#include <d3d11_1.h>
17
18#include <rhi/qrhi.h>
19
20#if QT_CONFIG(opengl)
21# include <qopenglcontext.h>
22# include <qopenglfunctions.h>
23# include <qoffscreensurface.h>
24#endif
25
27
28Q_STATIC_LOGGING_CATEGORY(qLcEvrD3DPresentEngine, "qt.multimedia.evrd3dpresentengine");
29
31{
32public:
33 IMFSampleVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample,
37 m_sample(sample),
38 m_mapMode(QtVideo::MapMode::NotMapped)
39 {
40 }
41
43 {
44 if (m_memSurface && m_mapMode != QtVideo::MapMode::NotMapped)
45 m_memSurface->UnlockRect();
46 }
47
49 {
51 return {};
52
53 D3DSURFACE_DESC desc;
54 if (m_memSurface) {
55 if (FAILED(m_memSurface->GetDesc(&desc)))
56 return {};
57
58 } else {
59 ComPtr<IMFMediaBuffer> buffer;
60 HRESULT hr = m_sample->GetBufferByIndex(0, buffer.GetAddressOf());
61 if (FAILED(hr))
62 return {};
63
64 ComPtr<IDirect3DSurface9> surface;
65 hr = MFGetService(buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9, (void **)(surface.GetAddressOf()));
66 if (FAILED(hr))
67 return {};
68
69 if (FAILED(surface->GetDesc(&desc)))
70 return {};
71
72 if (FAILED(m_device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, m_memSurface.GetAddressOf(), nullptr)))
73 return {};
74
75 if (FAILED(m_device->GetRenderTargetData(surface.Get(), m_memSurface.Get()))) {
76 m_memSurface.Reset();
77 return {};
78 }
79 }
80
81 D3DLOCKED_RECT rect;
82 if (FAILED(m_memSurface->LockRect(&rect, NULL, mode == QtVideo::MapMode::ReadOnly ? D3DLOCK_READONLY : 0)))
83 return {};
84
85 m_mapMode = mode;
86
88 mapData.planeCount = 1;
89 mapData.bytesPerLine[0] = (int)rect.Pitch;
90 mapData.data[0] = reinterpret_cast<uchar *>(rect.pBits);
91 mapData.dataSize[0] = (int)(rect.Pitch * desc.Height);
92 return mapData;
93 }
94
95 void unmap() override
96 {
97 if (m_mapMode == QtVideo::MapMode::NotMapped)
98 return;
99
100 m_mapMode = QtVideo::MapMode::NotMapped;
101 if (m_memSurface)
102 m_memSurface->UnlockRect();
103 }
104
105protected:
106 ComPtr<IDirect3DDevice9Ex> m_device;
107 ComPtr<IMFSample> m_sample;
108
109private:
110 ComPtr<IDirect3DSurface9> m_memSurface;
111 QtVideo::MapMode m_mapMode;
112};
113
115{
116public:
117 QVideoFrameD3D11Textures(std::unique_ptr<QRhiTexture> &&tex, ComPtr<ID3D11Texture2D> &&d3d11tex)
118 : m_tex(std::move(tex))
119 , m_d3d11tex(std::move(d3d11tex))
120 {}
121
122 QRhiTexture *texture(uint plane) const override
123 {
124 return plane == 0 ? m_tex.get() : nullptr;
125 };
126
127private:
128 std::unique_ptr<QRhiTexture> m_tex;
129 ComPtr<ID3D11Texture2D> m_d3d11tex;
130};
131
133{
134public:
135 D3D11TextureVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample,
136 HANDLE sharedHandle, QRhi *rhi)
137 : IMFSampleVideoBuffer(std::move(device), sample, rhi, QVideoFrame::RhiTextureHandle)
138 , m_sharedHandle(sharedHandle)
139 {}
140
141 std::unique_ptr<QVideoFrameTextures> mapTextures(QRhi *rhi) override
142 {
143 if (!rhi || rhi->backend() != QRhi::D3D11)
144 return {};
145
146 auto nh = static_cast<const QRhiD3D11NativeHandles*>(rhi->nativeHandles());
147 if (!nh)
148 return {};
149
150 auto dev = reinterpret_cast<ID3D11Device *>(nh->dev);
151 if (!dev)
152 return {};
153
154 ComPtr<ID3D11Texture2D> d3d11tex;
155 HRESULT hr = dev->OpenSharedResource(m_sharedHandle, __uuidof(ID3D11Texture2D), (void**)(d3d11tex.GetAddressOf()));
156 if (SUCCEEDED(hr)) {
157 D3D11_TEXTURE2D_DESC desc = {};
158 d3d11tex->GetDesc(&desc);
160 if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM)
162 else if (desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM)
164 else
165 return {};
166
167 std::unique_ptr<QRhiTexture> tex(rhi->newTexture(format, QSize{int(desc.Width), int(desc.Height)}, 1, {}));
168 tex->createFrom({quint64(d3d11tex.Get()), 0});
169 return std::make_unique<QVideoFrameD3D11Textures>(std::move(tex), std::move(d3d11tex));
170
171 } else {
172 qCDebug(qLcEvrD3DPresentEngine) << "Failed to obtain D3D11Texture2D from D3D9Texture2D handle";
173 }
174 return {};
175 }
176
177private:
178 HANDLE m_sharedHandle = nullptr;
179};
180
181#if QT_CONFIG(opengl)
182class QVideoFrameOpenGlTextures : public QVideoFrameTextures
183{
184 struct InterOpHandles {
185 GLuint textureName = 0;
186 HANDLE device = nullptr;
187 HANDLE texture = nullptr;
188 };
189
190public:
191 Q_DISABLE_COPY(QVideoFrameOpenGlTextures);
192
193 QVideoFrameOpenGlTextures(std::unique_ptr<QRhiTexture> &&tex, const WglNvDxInterop &wgl, InterOpHandles &handles)
194 : m_tex(std::move(tex))
195 , m_wgl(wgl)
196 , m_handles(handles)
197 {}
198
199 ~QVideoFrameOpenGlTextures() override {
201 if (!m_wgl.wglDXUnlockObjectsNV(m_handles.device, 1, &m_handles.texture))
202 qCDebug(qLcEvrD3DPresentEngine) << "Failed to unlock OpenGL texture";
203
204 if (!m_wgl.wglDXUnregisterObjectNV(m_handles.device, m_handles.texture))
205 qCDebug(qLcEvrD3DPresentEngine) << "Failed to unregister OpenGL texture";
206
208 if (funcs)
209 funcs->glDeleteTextures(1, &m_handles.textureName);
210 else
211 qCDebug(qLcEvrD3DPresentEngine) << "Could not delete texture, OpenGL context functions missing";
212
213 if (!m_wgl.wglDXCloseDeviceNV(m_handles.device))
214 qCDebug(qLcEvrD3DPresentEngine) << "Failed to close D3D-GL device";
215
216 } else {
217 qCDebug(qLcEvrD3DPresentEngine) << "Could not release texture, OpenGL context missing";
218 }
219 }
220
221 static std::unique_ptr<QVideoFrameOpenGlTextures> create(const WglNvDxInterop &wgl, QRhi *rhi,
222 IDirect3DDevice9Ex *device, IDirect3DTexture9 *texture,
223 HANDLE sharedHandle)
224 {
225 if (!rhi || rhi->backend() != QRhi::OpenGLES2)
226 return {};
227
229 return {};
230
231 InterOpHandles handles = {};
232 handles.device = wgl.wglDXOpenDeviceNV(device);
233 if (!handles.device) {
234 qCDebug(qLcEvrD3DPresentEngine) << "Failed to open D3D device";
235 return {};
236 }
237
238 wgl.wglDXSetResourceShareHandleNV(texture, sharedHandle);
239
241 if (funcs) {
242 funcs->glGenTextures(1, &handles.textureName);
243 handles.texture = wgl.wglDXRegisterObjectNV(handles.device, texture, handles.textureName,
244 GL_TEXTURE_2D, WglNvDxInterop::WGL_ACCESS_READ_ONLY_NV);
245 if (handles.texture) {
246 if (wgl.wglDXLockObjectsNV(handles.device, 1, &handles.texture)) {
247 D3DSURFACE_DESC desc;
248 texture->GetLevelDesc(0, &desc);
250 if (desc.Format == D3DFMT_A8R8G8B8)
252 else if (desc.Format == D3DFMT_A8B8G8R8)
254 else
255 return {};
256
257 std::unique_ptr<QRhiTexture> tex(rhi->newTexture(format, QSize{int(desc.Width), int(desc.Height)}, 1, {}));
258 tex->createFrom({quint64(handles.textureName), 0});
259 return std::make_unique<QVideoFrameOpenGlTextures>(std::move(tex), wgl, handles);
260 }
261
262 qCDebug(qLcEvrD3DPresentEngine) << "Failed to lock OpenGL texture";
263 wgl.wglDXUnregisterObjectNV(handles.device, handles.texture);
264 } else {
265 qCDebug(qLcEvrD3DPresentEngine) << "Could not register D3D9 texture in OpenGL";
266 }
267
268 funcs->glDeleteTextures(1, &handles.textureName);
269 } else {
270 qCDebug(qLcEvrD3DPresentEngine) << "Failed generate texture names, OpenGL context functions missing";
271 }
272 return {};
273 }
274
275 QRhiTexture *texture(uint plane) const override
276 {
277 return plane == 0 ? m_tex.get() : nullptr;
278 };
279private:
280 std::unique_ptr<QRhiTexture> m_tex;
281 WglNvDxInterop m_wgl;
282 InterOpHandles m_handles;
283};
284
285class OpenGlVideoBuffer: public IMFSampleVideoBuffer
286{
287public:
288 OpenGlVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample,
289 const WglNvDxInterop &wglNvDxInterop, HANDLE sharedHandle, QRhi *rhi)
290 : IMFSampleVideoBuffer(std::move(device), sample, rhi, QVideoFrame::RhiTextureHandle)
291 , m_sharedHandle(sharedHandle)
292 , m_wgl(wglNvDxInterop)
293 {}
294
295 std::unique_ptr<QVideoFrameTextures> mapTextures(QRhi *rhi) override
296 {
297 if (!m_texture) {
298 ComPtr<IMFMediaBuffer> buffer;
299 HRESULT hr = m_sample->GetBufferByIndex(0, buffer.GetAddressOf());
300 if (FAILED(hr))
301 return {};
302
303 ComPtr<IDirect3DSurface9> surface;
304 hr = MFGetService(buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9,
305 (void **)(surface.GetAddressOf()));
306 if (FAILED(hr))
307 return {};
308
309 hr = surface->GetContainer(IID_IDirect3DTexture9, (void **)m_texture.GetAddressOf());
310 if (FAILED(hr))
311 return {};
312 }
313
314 return QVideoFrameOpenGlTextures::create(m_wgl, rhi, m_device.Get(), m_texture.Get(), m_sharedHandle);
315 }
316
317private:
318 HANDLE m_sharedHandle = nullptr;
319 WglNvDxInterop m_wgl;
320 ComPtr<IDirect3DTexture9> m_texture;
321};
322#endif
323
325 : m_deviceResetToken(0)
326{
327 ZeroMemory(&m_displayMode, sizeof(m_displayMode));
328 setSink(sink);
329}
330
335
337{
338 if (sink == m_sink)
339 return;
340
341 m_sink = sink;
342
344 m_device.Reset();
345 m_devices.Reset();
346 m_D3D9.Reset();
347
348 if (!m_sink)
349 return;
350
351 HRESULT hr = initializeD3D();
352
353 if (SUCCEEDED(hr)) {
354 hr = createD3DDevice();
355 if (FAILED(hr))
356 qWarning("Failed to create D3D device");
357 } else {
358 qWarning("Failed to initialize D3D");
359 }
360}
361
362HRESULT D3DPresentEngine::initializeD3D()
363{
364 HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, m_D3D9.GetAddressOf());
365
366 if (SUCCEEDED(hr))
367 hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, m_devices.GetAddressOf());
368
369 return hr;
370}
371
372static bool findD3D11AdapterID(QRhi &rhi, IDirect3D9Ex *D3D9, UINT &adapterID)
373{
374 auto nh = static_cast<const QRhiD3D11NativeHandles*>(rhi.nativeHandles());
375 if (D3D9 && nh) {
376 for (auto i = 0u; i < D3D9->GetAdapterCount(); ++i) {
377 LUID luid = {};
378 D3D9->GetAdapterLUID(i, &luid);
379 if (luid.LowPart == nh->adapterLuidLow && luid.HighPart == nh->adapterLuidHigh) {
380 adapterID = i;
381 return true;
382 }
383 }
384 }
385
386 return false;
387}
388
389#if QT_CONFIG(opengl)
390template <typename T>
391static bool getProc(const QOpenGLContext *ctx, T &fn, const char *fName)
392{
393 fn = reinterpret_cast<T>(ctx->getProcAddress(fName));
394 return fn != nullptr;
395}
396
397static bool readWglNvDxInteropProc(WglNvDxInterop &f)
398{
399 QScopedPointer<QOffscreenSurface> surface(new QOffscreenSurface);
400 surface->create();
401 QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);
402 ctx->create();
403 ctx->makeCurrent(surface.get());
404
405 auto wglGetExtensionsStringARB = reinterpret_cast<const char* (WINAPI* )(HDC)>
406 (ctx->getProcAddress("wglGetExtensionsStringARB"));
407 if (!wglGetExtensionsStringARB) {
408 qCDebug(qLcEvrD3DPresentEngine) << "WGL extensions missing (no wglGetExtensionsStringARB function)";
409 return false;
410 }
411
412 HWND hwnd = ::GetShellWindow();
413 auto dc = ::GetDC(hwnd);
414
415 const char *wglExtString = wglGetExtensionsStringARB(dc);
416 if (!wglExtString)
417 qCDebug(qLcEvrD3DPresentEngine) << "WGL extensions missing (wglGetExtensionsStringARB returned null)";
418
419 bool hasExtension = wglExtString && strstr(wglExtString, "WGL_NV_DX_interop");
420 ReleaseDC(hwnd, dc);
421 if (!hasExtension) {
422 qCDebug(qLcEvrD3DPresentEngine) << "WGL_NV_DX_interop missing";
423 return false;
424 }
425
426 return getProc(ctx.get(), f.wglDXOpenDeviceNV, "wglDXOpenDeviceNV")
427 && getProc(ctx.get(), f.wglDXCloseDeviceNV, "wglDXCloseDeviceNV")
428 && getProc(ctx.get(), f.wglDXSetResourceShareHandleNV, "wglDXSetResourceShareHandleNV")
429 && getProc(ctx.get(), f.wglDXRegisterObjectNV, "wglDXRegisterObjectNV")
430 && getProc(ctx.get(), f.wglDXUnregisterObjectNV, "wglDXUnregisterObjectNV")
431 && getProc(ctx.get(), f.wglDXLockObjectsNV, "wglDXLockObjectsNV")
432 && getProc(ctx.get(), f.wglDXUnlockObjectsNV, "wglDXUnlockObjectsNV");
433}
434#endif
435
436namespace {
437
438bool hwTextureRenderingEnabled() {
439 // add possibility for an user to opt-out HW video rendering
440 // using the same env. variable as for FFmpeg backend
441 static bool isDisableConversionSet = false;
442 static const int disableHwConversion = qEnvironmentVariableIntValue(
443 "QT_DISABLE_HW_TEXTURES_CONVERSION", &isDisableConversionSet);
444
445 return !isDisableConversionSet || !disableHwConversion;
446}
447
448}
449
450HRESULT D3DPresentEngine::createD3DDevice()
451{
452 if (!m_D3D9 || !m_devices)
453 return MF_E_NOT_INITIALIZED;
454
455 m_useTextureRendering = false;
456 UINT adapterID = 0;
457
458 if (hwTextureRenderingEnabled()) {
459 QRhi *rhi = m_sink ? m_sink->rhi() : nullptr;
460 if (rhi) {
461 if (rhi->backend() == QRhi::D3D11) {
462 m_useTextureRendering = findD3D11AdapterID(*rhi, m_D3D9.Get(), adapterID);
463#if QT_CONFIG(opengl)
464 } else if (rhi->backend() == QRhi::OpenGLES2) {
465 m_useTextureRendering = readWglNvDxInteropProc(m_wglNvDxInterop);
466#endif
467 } else {
468 qCDebug(qLcEvrD3DPresentEngine) << "Not supported RHI backend type";
469 }
470 } else {
471 qCDebug(qLcEvrD3DPresentEngine) << "No RHI associated with this sink";
472 }
473
474 if (!m_useTextureRendering)
475 qCDebug(qLcEvrD3DPresentEngine) << "Could not find compatible RHI adapter, zero copy disabled";
476 }
477
478 D3DCAPS9 ddCaps;
479 ZeroMemory(&ddCaps, sizeof(ddCaps));
480
481 HRESULT hr = m_D3D9->GetDeviceCaps(adapterID, D3DDEVTYPE_HAL, &ddCaps);
482 if (FAILED(hr))
483 return hr;
484
485 DWORD vp = 0;
486 if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
487 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
488 else
489 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
490
491 D3DPRESENT_PARAMETERS pp;
492 ZeroMemory(&pp, sizeof(pp));
493
494 pp.BackBufferWidth = 1;
495 pp.BackBufferHeight = 1;
496 pp.BackBufferCount = 1;
497 pp.Windowed = TRUE;
498 pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
499 pp.BackBufferFormat = D3DFMT_UNKNOWN;
500 pp.hDeviceWindow = nullptr;
501 pp.Flags = D3DPRESENTFLAG_VIDEO;
502 pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
503
504 ComPtr<IDirect3DDevice9Ex> device;
505
506 hr = m_D3D9->CreateDeviceEx(
507 adapterID,
508 D3DDEVTYPE_HAL,
509 pp.hDeviceWindow,
510 vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
511 &pp,
512 NULL,
513 device.GetAddressOf()
514 );
515 if (FAILED(hr))
516 return hr;
517
518 hr = m_D3D9->GetAdapterDisplayMode(adapterID, &m_displayMode);
519 if (FAILED(hr))
520 return hr;
521
522 hr = m_devices->ResetDevice(device.Get(), m_deviceResetToken);
523 if (FAILED(hr))
524 return hr;
525
526 m_device = device;
527 return hr;
528}
529
531{
532 return m_device.Get() != nullptr;
533}
534
536{
537 m_surfaceFormat = QVideoFrameFormat();
538}
539
541{
542 HRESULT hr = S_OK;
543
544 if (riid == __uuidof(IDirect3DDeviceManager9)) {
545 if (!m_devices) {
546 hr = MF_E_UNSUPPORTED_SERVICE;
547 } else {
548 *ppv = m_devices.Get();
549 m_devices->AddRef();
550 }
551 } else {
552 hr = MF_E_UNSUPPORTED_SERVICE;
553 }
554
555 return hr;
556}
557
559{
560 if (!m_D3D9 || !m_device)
561 return E_FAIL;
562
563 HRESULT hr = S_OK;
564
565 D3DDISPLAYMODE mode;
566 D3DDEVICE_CREATION_PARAMETERS params;
567
568 hr = m_device->GetCreationParameters(&params);
569 if (FAILED(hr))
570 return hr;
571
572 UINT uAdapter = params.AdapterOrdinal;
573 D3DDEVTYPE type = params.DeviceType;
574
575 hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode);
576 if (FAILED(hr))
577 return hr;
578
579 hr = m_D3D9->CheckDeviceFormat(uAdapter, type, mode.Format,
580 D3DUSAGE_RENDERTARGET,
581 D3DRTYPE_SURFACE,
582 format);
583 if (FAILED(hr))
584 return hr;
585
586 bool ok = format == D3DFMT_X8R8G8B8
587 || format == D3DFMT_A8R8G8B8
588 || format == D3DFMT_X8B8G8R8
589 || format == D3DFMT_A8B8G8R8;
590
591 return ok ? S_OK : D3DERR_NOTAVAILABLE;
592}
593
595 QList<ComPtr<IMFSample>> &videoSampleQueue,
597{
598 if (!format || !m_device)
599 return MF_E_UNEXPECTED;
600
601 HRESULT hr = S_OK;
603
604 UINT32 width = 0, height = 0;
605 hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height);
606 if (FAILED(hr))
607 return hr;
608
609 if (frameSize.isValid() && !frameSize.isEmpty()) {
610 width = frameSize.width();
611 height = frameSize.height();
612 }
613
614 DWORD d3dFormat = 0;
615 hr = qt_evr_getFourCC(format, &d3dFormat);
616 if (FAILED(hr))
617 return hr;
618
619 // FIXME: RHI defines only RGBA, thus add the alpha channel to the selected format
620 if (d3dFormat == D3DFMT_X8R8G8B8)
621 d3dFormat = D3DFMT_A8R8G8B8;
622 else if (d3dFormat == D3DFMT_X8B8G8R8)
623 d3dFormat = D3DFMT_A8B8G8R8;
624
625 for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) {
626 // texture ref cnt is increased by GetSurfaceLevel()/MFCreateVideoSampleFromSurface()
627 // below, so it will be destroyed only when the sample pool is released.
628 ComPtr<IDirect3DTexture9> texture;
629 HANDLE sharedHandle = nullptr;
630 hr = m_device->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)d3dFormat, D3DPOOL_DEFAULT, texture.GetAddressOf(), &sharedHandle);
631 if (FAILED(hr))
632 break;
633
634 ComPtr<IDirect3DSurface9> surface;
635 hr = texture->GetSurfaceLevel(0, surface.GetAddressOf());
636 if (FAILED(hr))
637 break;
638
639 ComPtr<IMFSample> videoSample;
640 hr = MFCreateVideoSampleFromSurface(surface.Get(), videoSample.GetAddressOf());
641 if (FAILED(hr))
642 break;
643
644 m_sampleTextureHandle[i] = {videoSample.Get(), sharedHandle};
645 videoSampleQueue.append(videoSample);
646 }
647
648 if (SUCCEEDED(hr)) {
649 m_surfaceFormat = QVideoFrameFormat(QSize(width, height), qt_evr_pixelFormatFromD3DFormat(d3dFormat));
650 } else {
652 }
653
654 return hr;
655}
656
657QVideoFrame D3DPresentEngine::makeVideoFrame(const ComPtr<IMFSample> &sample)
658{
659 if (!sample)
660 return {};
661
662 HANDLE sharedHandle = nullptr;
663 for (const auto &p : m_sampleTextureHandle)
664 if (p.first == sample.Get())
665 sharedHandle = p.second;
666
667 std::unique_ptr<IMFSampleVideoBuffer> vb;
668 QRhi *rhi = m_sink ? m_sink->rhi() : nullptr;
669 if (m_useTextureRendering && sharedHandle && rhi) {
670 if (rhi->backend() == QRhi::D3D11) {
671 vb = std::make_unique<D3D11TextureVideoBuffer>(m_device, sample, sharedHandle, rhi);
672#if QT_CONFIG(opengl)
673 } else if (rhi->backend() == QRhi::OpenGLES2) {
674 vb = std::make_unique<OpenGlVideoBuffer>(m_device, sample, m_wglNvDxInterop,
675 sharedHandle, rhi);
676#endif
677 }
678 }
679
680 if (!vb)
681 vb = std::make_unique<IMFSampleVideoBuffer>(m_device, sample, rhi);
682
683 QVideoFrame frame = QVideoFramePrivate::createFrame(std::move(vb), m_surfaceFormat);
684
685 // WMF uses 100-nanosecond units, Qt uses microseconds
686 LONGLONG startTime = 0;
687 auto hr = sample->GetSampleTime(&startTime);
688 if (SUCCEEDED(hr)) {
689 frame.setStartTime(startTime / 10);
690
691 LONGLONG duration = -1;
692 if (SUCCEEDED(sample->GetSampleDuration(&duration)))
693 frame.setEndTime((startTime + duration) / 10);
694 }
695
696 return frame;
697}
698
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)
D3DPresentEngine(QVideoSink *sink)
HRESULT checkFormat(D3DFORMAT format)
QVideoFrame makeVideoFrame(const ComPtr< IMFSample > &sample)
ComPtr< IMFSample > m_sample
ComPtr< IDirect3DDevice9Ex > m_device
MapData map(QtVideo::MapMode mode) override
Maps the planes of a video buffer to memory.
void unmap() override
Releases the memory mapped by the map() function.
IMFSampleVideoBuffer(ComPtr< IDirect3DDevice9Ex > device, const ComPtr< IMFSample > &sample, QRhi *rhi, QVideoFrame::HandleType type=QVideoFrame::NoHandle)
QRhi * rhi() const
QVideoFrameFormat format() const override
Gets \l QVideoFrameFormat of the underlying video buffer.
Definition qlist.h:76
\inmodule QtGui
\inmodule QtGui
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
\inmodule QtGui
Definition qrhi.h:895
Format
Specifies the texture format.
Definition qrhi.h:914
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1805
Implementation backend() const
Definition qrhi.cpp:8659
@ D3D11
Definition qrhi.h:1811
@ OpenGLES2
Definition qrhi.h:1810
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10570
const QRhiNativeHandles * nativeHandles()
Definition qrhi.cpp:10145
\inmodule QtCore
Definition qsize.h:25
QVideoFrameD3D11Textures(std::unique_ptr< QRhiTexture > &&tex, ComPtr< ID3D11Texture2D > &&d3d11tex)
QRhiTexture * texture(uint plane) const override
The QVideoFrameFormat class specifies the stream format of a video presentation surface.
static QVideoFrame createFrame(std::unique_ptr< Buffer > buffer, QVideoFrameFormat format)
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
HandleType
Identifies the type of a video buffers handle.
Definition qvideoframe.h:32
The QVideoSink class represents a generic sink for video data.
Definition qvideosink.h:22
QRhi * rhi() const
Returns the QRhi instance being used to create texture data in the video frames.
EGLContext ctx
static VulkanServerBufferGlFunctions * funcs
rect
[4]
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.
Enumerations for camera and video functionality.
MapMode
Enumerates how a video buffer's data is mapped to system memory.
Definition qtvideo.h:25
void * HANDLE
qint64 startTime
#define qWarning
Definition qlogging.h:167
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
GLenum mode
GLint GLsizei GLsizei height
GLfloat GLfloat f
GLenum GLuint buffer
GLint GLsizei width
GLenum type
GLenum GLuint texture
GLint GLsizei GLsizei GLenum format
void ** params
GLsizei GLenum GLboolean sink
GLfloat GLfloat p
[1]
static QAbstractVideoBuffer::MapData mapData(const camera_frame_nv12_t &frame, unsigned char *baseAddress)
static constexpr QSize frameSize(const T &frame)
#define GLuint
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
unsigned char uchar
Definition qtypes.h:32
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
IUIViewSettingsInterop __RPC__in REFIID riid
IUIViewSettingsInterop __RPC__in REFIID __RPC__deref_out_opt void ** ppv
long HRESULT
QFrame frame
[0]
view create()
The QAbstractVideoBuffer::MapData structure describes the mapped plane layout.