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