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;
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, 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);
415 bool hasExtension = strstr(wglGetExtensionsStringARB(dc),
"WGL_NV_DX_interop");
418 qCDebug(qLcEvrD3DPresentEngine) <<
"WGL_NV_DX_interop missing";
422 return getProc(
ctx.get(),
f.wglDXOpenDeviceNV,
"wglDXOpenDeviceNV")
423 && getProc(
ctx.get(),
f.wglDXCloseDeviceNV,
"wglDXCloseDeviceNV")
424 && getProc(
ctx.get(),
f.wglDXSetResourceShareHandleNV,
"wglDXSetResourceShareHandleNV")
425 && getProc(
ctx.get(),
f.wglDXRegisterObjectNV,
"wglDXRegisterObjectNV")
426 && getProc(
ctx.get(),
f.wglDXUnregisterObjectNV,
"wglDXUnregisterObjectNV")
427 && getProc(
ctx.get(),
f.wglDXLockObjectsNV,
"wglDXLockObjectsNV")
428 && getProc(
ctx.get(),
f.wglDXUnlockObjectsNV,
"wglDXUnlockObjectsNV");
432HRESULT D3DPresentEngine::createD3DDevice()
434 if (!m_D3D9 || !m_devices)
435 return MF_E_NOT_INITIALIZED;
437 m_useTextureRendering =
false;
439 QRhi *rhi = m_sink ? m_sink->
rhi() :
nullptr;
445 m_useTextureRendering = readWglNvDxInteropProc(m_wglNvDxInterop);
448 qCDebug(qLcEvrD3DPresentEngine) <<
"Not supported RHI backend type";
451 qCDebug(qLcEvrD3DPresentEngine) <<
"No RHI associated with this sink";
454 if (!m_useTextureRendering)
455 qCDebug(qLcEvrD3DPresentEngine) <<
"Could not find compatible RHI adapter, zero copy disabled";
458 ZeroMemory(&ddCaps,
sizeof(ddCaps));
460 HRESULT hr = m_D3D9->GetDeviceCaps(adapterID, D3DDEVTYPE_HAL, &ddCaps);
465 if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
466 vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
468 vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
470 D3DPRESENT_PARAMETERS pp;
471 ZeroMemory(&pp,
sizeof(pp));
473 pp.BackBufferWidth = 1;
474 pp.BackBufferHeight = 1;
475 pp.BackBufferCount = 1;
477 pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
478 pp.BackBufferFormat = D3DFMT_UNKNOWN;
479 pp.hDeviceWindow =
nullptr;
480 pp.Flags = D3DPRESENTFLAG_VIDEO;
481 pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
483 ComPtr<IDirect3DDevice9Ex>
device;
485 hr = m_D3D9->CreateDeviceEx(
489 vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
497 hr = m_D3D9->GetAdapterDisplayMode(adapterID, &m_displayMode);
501 hr = m_devices->ResetDevice(
device.Get(), m_deviceResetToken);
511 return m_device.Get() !=
nullptr;
523 if (
riid == __uuidof(IDirect3DDeviceManager9)) {
525 hr = MF_E_UNSUPPORTED_SERVICE;
527 *
ppv = m_devices.Get();
531 hr = MF_E_UNSUPPORTED_SERVICE;
539 if (!m_D3D9 || !m_device)
545 D3DDEVICE_CREATION_PARAMETERS
params;
547 hr = m_device->GetCreationParameters(&
params);
551 UINT uAdapter =
params.AdapterOrdinal;
554 hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &
mode);
558 hr = m_D3D9->CheckDeviceFormat(uAdapter,
type,
mode.Format,
559 D3DUSAGE_RENDERTARGET,
566 ||
format == D3DFMT_A8R8G8B8
567 ||
format == D3DFMT_X8B8G8R8
568 ||
format == D3DFMT_A8B8G8R8;
570 return ok ? S_OK : D3DERR_NOTAVAILABLE;
576 return MF_E_UNEXPECTED;
597 if (d3dFormat == D3DFMT_X8R8G8B8)
598 d3dFormat = D3DFMT_A8R8G8B8;
599 else if (d3dFormat == D3DFMT_X8B8G8R8)
600 d3dFormat = D3DFMT_A8B8G8R8;
602 for (
int i = 0;
i < PRESENTER_BUFFER_COUNT;
i++) {
605 ComPtr<IDirect3DTexture9>
texture;
606 HANDLE sharedHandle =
nullptr;
607 hr = m_device->CreateTexture(
width,
height, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)d3dFormat, D3DPOOL_DEFAULT,
texture.GetAddressOf(), &sharedHandle);
611 ComPtr<IDirect3DSurface9> surface;
612 hr =
texture->GetSurfaceLevel(0, surface.GetAddressOf());
616 ComPtr<IMFSample> videoSample;
617 hr = MFCreateVideoSampleFromSurface(surface.Get(), videoSample.GetAddressOf());
621 m_sampleTextureHandle[
i] = {videoSample.Get(), sharedHandle};
622 videoSampleQueue.
append(videoSample.Detach());
639 HANDLE sharedHandle =
nullptr;
640 for (
const auto &
p : m_sampleTextureHandle)
641 if (
p.first == sample)
642 sharedHandle =
p.second;
645 QRhi *rhi = m_sink ? m_sink->
rhi() :
nullptr;
646 if (m_useTextureRendering && sharedHandle && rhi) {
651 vb =
new OpenGlVideoBuffer(m_device, sample, m_wglNvDxInterop, sharedHandle, rhi);
663 auto hr = sample->GetSampleTime(&
startTime);
667 LONGLONG duration = -1;
668 if (SUCCEEDED(sample->GetSampleDuration(&duration)))
IOBluetoothDevice * device
std::unique_ptr< QVideoFrameTextures > mapTextures(QRhi *rhi) override
D3D11TextureVideoBuffer(ComPtr< IDirect3DDevice9Ex > device, IMFSample *sample, HANDLE sharedHandle, QRhi *rhi)
HRESULT createVideoSamples(IMFMediaType *format, QList< IMFSample * > &videoSampleQueue, QSize frameSize)
void setSink(QVideoSink *sink)
QVideoFrame makeVideoFrame(IMFSample *sample)
HRESULT getService(REFGUID guidService, REFIID riid, void **ppv)
virtual ~D3DPresentEngine()
friend class IMFSampleVideoBuffer
D3DPresentEngine(QVideoSink *sink)
HRESULT checkFormat(D3DFORMAT format)
The QAbstractVideoBuffer class is an abstraction for video data. \inmodule QtMultimedia.
void append(parameter_type t)
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
QOpenGLFunctions * functions() const
Get the QOpenGLFunctions instance for this context.
The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
\variable QRhiD3D11InitParams::enableDebugLayer
Format
Specifies the texture format.
Implementation backend() const
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
const QRhiNativeHandles * nativeHandles()
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
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)
unsigned long long quint64
IUIViewSettingsInterop __RPC__in REFIID riid
IUIViewSettingsInterop __RPC__in REFIID __RPC__deref_out_opt void ** ppv