Revision control

- // Copyright (C) 2016 The Qt Company Ltd.
- // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
- #include "evrd3dpresentengine_p.h"
-
- #include "evrhelpers_p.h"
-
- #include <private/qhwvideobuffer_p.h>
- #include <private/qvideoframe_p.h>
- #include <qvideoframe.h>
- #include <QDebug>
- #include <qthread.h>
- #include <qvideosink.h>
- #include <qloggingcategory.h>
-
- #include <d3d11_1.h>
-
- #include <rhi/qrhi.h>
-
- #if QT_CONFIG(opengl)
- # include <qopenglcontext.h>
- # include <qopenglfunctions.h>
- # include <qoffscreensurface.h>
- #endif
-
- QT_BEGIN_NAMESPACE
-
- Q_STATIC_LOGGING_CATEGORY(qLcEvrD3DPresentEngine, "qt.multimedia.evrd3dpresentengine");
-
- class IMFSampleVideoBuffer : public QHwVideoBuffer
- {
- public:
- IMFSampleVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample)
- : m_device(device), m_sample(sample), m_mapMode(QVideoFrame::NotMapped)
- {
- }
-
- ~IMFSampleVideoBuffer() override
- {
- if (m_memSurface && m_mapMode != QVideoFrame::NotMapped)
- m_memSurface->UnlockRect();
- }
-
- MapData map(QVideoFrame::MapMode mode) override
- {
- if (!m_sample || m_mapMode != QVideoFrame::NotMapped || mode != QVideoFrame::ReadOnly)
- return {};
-
- D3DSURFACE_DESC desc;
- if (m_memSurface) {
- if (FAILED(m_memSurface->GetDesc(&desc)))
- return {};
-
- } else {
- ComPtr<IMFMediaBuffer> buffer;
- HRESULT hr = m_sample->GetBufferByIndex(0, buffer.GetAddressOf());
- if (FAILED(hr))
- return {};
-
- ComPtr<IDirect3DSurface9> surface;
- hr = MFGetService(buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9, (void **)(surface.GetAddressOf()));
- if (FAILED(hr))
- return {};
-
- if (FAILED(surface->GetDesc(&desc)))
- return {};
-
- if (FAILED(m_device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, m_memSurface.GetAddressOf(), nullptr)))
- return {};
-
- if (FAILED(m_device->GetRenderTargetData(surface.Get(), m_memSurface.Get()))) {
- m_memSurface.Reset();
- return {};
- }
- }
-
- D3DLOCKED_RECT rect;
- if (FAILED(m_memSurface->LockRect(&rect, NULL, mode == QVideoFrame::ReadOnly ? D3DLOCK_READONLY : 0)))
- return {};
-
- m_mapMode = mode;
-
- MapData mapData;
- mapData.planeCount = 1;
- mapData.bytesPerLine[0] = (int)rect.Pitch;
- mapData.data[0] = reinterpret_cast<uchar *>(rect.pBits);
- mapData.dataSize[0] = (int)(rect.Pitch * desc.Height);
- return mapData;
- }
-
- void unmap() override
- {
- if (m_mapMode == QVideoFrame::NotMapped)
- return;
-
- m_mapMode = QVideoFrame::NotMapped;
- if (m_memSurface)
- m_memSurface->UnlockRect();
- }
-
- protected:
- ComPtr<IDirect3DDevice9Ex> m_device;
- ComPtr<IMFSample> m_sample;
-
- private:
- ComPtr<IDirect3DSurface9> m_memSurface;
- QVideoFrame::MapMode m_mapMode;
- };
-
- class QVideoFrameD3D11Textures: public QVideoFrameTextures
- {
- public:
- QVideoFrameD3D11Textures(std::unique_ptr<QRhiTexture> &&tex, ComPtr<ID3D11Texture2D> &&d3d11tex)
- : m_tex(std::move(tex))
- , m_d3d11tex(std::move(d3d11tex))
- {}
-
- QRhiTexture *texture(uint plane) const override { return plane == 0 ? m_tex.get() : nullptr; }
-
- private:
- std::unique_ptr<QRhiTexture> m_tex;
- ComPtr<ID3D11Texture2D> m_d3d11tex;
- };
-
- class D3D11TextureVideoBuffer: public IMFSampleVideoBuffer
- {
- public:
- D3D11TextureVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample,
- HANDLE sharedHandle)
- : IMFSampleVideoBuffer(std::move(device), sample), m_sharedHandle(sharedHandle)
- {}
-
- QVideoFrameTexturesUPtr mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr& /*oldTextures*/) override
- {
- if (rhi.backend() != QRhi::D3D11)
- return {};
-
- auto nh = static_cast<const QRhiD3D11NativeHandles*>(rhi.nativeHandles());
- if (!nh)
- return {};
-
- auto dev = reinterpret_cast<ID3D11Device *>(nh->dev);
- if (!dev)
- return {};
-
- ComPtr<ID3D11Texture2D> d3d11tex;
- HRESULT hr = dev->OpenSharedResource(m_sharedHandle, __uuidof(ID3D11Texture2D), (void**)(d3d11tex.GetAddressOf()));
- if (SUCCEEDED(hr)) {
- D3D11_TEXTURE2D_DESC desc = {};
- d3d11tex->GetDesc(&desc);
- QRhiTexture::Format format;
- if (desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM)
- format = QRhiTexture::BGRA8;
- else if (desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM)
- format = QRhiTexture::RGBA8;
- else
- return {};
-
- std::unique_ptr<QRhiTexture> tex(rhi.newTexture(format, QSize{int(desc.Width), int(desc.Height)}, 1, {}));
- tex->createFrom({quint64(d3d11tex.Get()), 0});
- return std::make_unique<QVideoFrameD3D11Textures>(std::move(tex), std::move(d3d11tex));
-
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to obtain D3D11Texture2D from D3D9Texture2D handle";
- }
- return {};
- }
-
- private:
- HANDLE m_sharedHandle = nullptr;
- };
-
- #if QT_CONFIG(opengl)
- class QVideoFrameOpenGlTextures : public QVideoFrameTextures
- {
- struct InterOpHandles {
- GLuint textureName = 0;
- HANDLE device = nullptr;
- HANDLE texture = nullptr;
- };
-
- public:
- Q_DISABLE_COPY(QVideoFrameOpenGlTextures)
-
- QVideoFrameOpenGlTextures(std::unique_ptr<QRhiTexture> &&tex, const WglNvDxInterop &wgl, InterOpHandles &handles)
- : m_tex(std::move(tex))
- , m_wgl(wgl)
- , m_handles(handles)
- {}
-
- ~QVideoFrameOpenGlTextures() override {
- if (QOpenGLContext::currentContext()) {
- if (!m_wgl.wglDXUnlockObjectsNV(m_handles.device, 1, &m_handles.texture))
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to unlock OpenGL texture";
-
- if (!m_wgl.wglDXUnregisterObjectNV(m_handles.device, m_handles.texture))
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to unregister OpenGL texture";
-
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- if (funcs)
- funcs->glDeleteTextures(1, &m_handles.textureName);
- else
- qCDebug(qLcEvrD3DPresentEngine) << "Could not delete texture, OpenGL context functions missing";
-
- if (!m_wgl.wglDXCloseDeviceNV(m_handles.device))
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to close D3D-GL device";
-
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "Could not release texture, OpenGL context missing";
- }
- }
-
- static std::unique_ptr<QVideoFrameOpenGlTextures> create(const WglNvDxInterop &wgl, QRhi *rhi,
- IDirect3DDevice9Ex *device, IDirect3DTexture9 *texture,
- HANDLE sharedHandle)
- {
- if (!rhi || rhi->backend() != QRhi::OpenGLES2)
- return {};
-
- if (!QOpenGLContext::currentContext())
- return {};
-
- InterOpHandles handles = {};
- handles.device = wgl.wglDXOpenDeviceNV(device);
- if (!handles.device) {
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to open D3D device";
- return {};
- }
-
- wgl.wglDXSetResourceShareHandleNV(texture, sharedHandle);
-
- QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions();
- if (funcs) {
- funcs->glGenTextures(1, &handles.textureName);
- handles.texture = wgl.wglDXRegisterObjectNV(handles.device, texture, handles.textureName,
- GL_TEXTURE_2D, WglNvDxInterop::WGL_ACCESS_READ_ONLY_NV);
- if (handles.texture) {
- if (wgl.wglDXLockObjectsNV(handles.device, 1, &handles.texture)) {
- D3DSURFACE_DESC desc;
- texture->GetLevelDesc(0, &desc);
- QRhiTexture::Format format;
- if (desc.Format == D3DFMT_A8R8G8B8)
- format = QRhiTexture::BGRA8;
- else if (desc.Format == D3DFMT_A8B8G8R8)
- format = QRhiTexture::RGBA8;
- else
- return {};
-
- std::unique_ptr<QRhiTexture> tex(rhi->newTexture(format, QSize{int(desc.Width), int(desc.Height)}, 1, {}));
- tex->createFrom({quint64(handles.textureName), 0});
- return std::make_unique<QVideoFrameOpenGlTextures>(std::move(tex), wgl, handles);
- }
-
- qCDebug(qLcEvrD3DPresentEngine) << "Failed to lock OpenGL texture";
- wgl.wglDXUnregisterObjectNV(handles.device, handles.texture);
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "Could not register D3D9 texture in OpenGL";
- }
-
- funcs->glDeleteTextures(1, &handles.textureName);
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "Failed generate texture names, OpenGL context functions missing";
- }
- return {};
- }
-
- QRhiTexture *texture(uint plane) const override { return plane == 0 ? m_tex.get() : nullptr; }
-
- private:
- std::unique_ptr<QRhiTexture> m_tex;
- WglNvDxInterop m_wgl;
- InterOpHandles m_handles;
- };
-
- class OpenGlVideoBuffer: public IMFSampleVideoBuffer
- {
- public:
- OpenGlVideoBuffer(ComPtr<IDirect3DDevice9Ex> device, const ComPtr<IMFSample> &sample,
- const WglNvDxInterop &wglNvDxInterop, HANDLE sharedHandle)
- : IMFSampleVideoBuffer(std::move(device), sample)
- , m_sharedHandle(sharedHandle)
- , m_wgl(wglNvDxInterop)
- {}
-
- QVideoFrameTexturesUPtr mapTextures(QRhi &rhi, QVideoFrameTexturesUPtr& /*oldTextures*/) override
- {
- if (!m_texture) {
- ComPtr<IMFMediaBuffer> buffer;
- HRESULT hr = m_sample->GetBufferByIndex(0, buffer.GetAddressOf());
- if (FAILED(hr))
- return {};
-
- ComPtr<IDirect3DSurface9> surface;
- hr = MFGetService(buffer.Get(), MR_BUFFER_SERVICE, IID_IDirect3DSurface9,
- (void **)(surface.GetAddressOf()));
- if (FAILED(hr))
- return {};
-
- hr = surface->GetContainer(IID_IDirect3DTexture9, (void **)m_texture.GetAddressOf());
- if (FAILED(hr))
- return {};
- }
-
- return QVideoFrameOpenGlTextures::create(m_wgl, &rhi, m_device.Get(), m_texture.Get(), m_sharedHandle);
- }
-
- private:
- HANDLE m_sharedHandle = nullptr;
- WglNvDxInterop m_wgl;
- ComPtr<IDirect3DTexture9> m_texture;
- };
- #endif
-
- D3DPresentEngine::D3DPresentEngine(QVideoSink *sink)
- : m_deviceResetToken(0)
- {
- ZeroMemory(&m_displayMode, sizeof(m_displayMode));
- setSink(sink);
- }
-
- D3DPresentEngine::~D3DPresentEngine()
- {
- releaseResources();
- }
-
- void D3DPresentEngine::setSink(QVideoSink *sink)
- {
- if (sink == m_sink)
- return;
-
- m_sink = sink;
-
- releaseResources();
- m_device.Reset();
- m_devices.Reset();
- m_D3D9.Reset();
-
- if (!m_sink)
- return;
-
- HRESULT hr = initializeD3D();
-
- if (SUCCEEDED(hr)) {
- hr = createD3DDevice();
- if (FAILED(hr))
- qWarning("Failed to create D3D device");
- } else {
- qWarning("Failed to initialize D3D");
- }
- }
-
- HRESULT D3DPresentEngine::initializeD3D()
- {
- HRESULT hr = Direct3DCreate9Ex(D3D_SDK_VERSION, m_D3D9.GetAddressOf());
-
- if (SUCCEEDED(hr))
- hr = DXVA2CreateDirect3DDeviceManager9(&m_deviceResetToken, m_devices.GetAddressOf());
-
- return hr;
- }
-
- static bool findD3D11AdapterID(QRhi &rhi, IDirect3D9Ex *D3D9, UINT &adapterID)
- {
- auto nh = static_cast<const QRhiD3D11NativeHandles*>(rhi.nativeHandles());
- if (D3D9 && nh) {
- for (auto i = 0u; i < D3D9->GetAdapterCount(); ++i) {
- LUID luid = {};
- D3D9->GetAdapterLUID(i, &luid);
- if (luid.LowPart == nh->adapterLuidLow && luid.HighPart == nh->adapterLuidHigh) {
- adapterID = i;
- return true;
- }
- }
- }
-
- return false;
- }
-
- #if QT_CONFIG(opengl)
- template <typename T>
- static bool getProc(const QOpenGLContext *ctx, T &fn, const char *fName)
- {
- fn = reinterpret_cast<T>(ctx->getProcAddress(fName));
- return fn != nullptr;
- }
-
- static bool readWglNvDxInteropProc(WglNvDxInterop &f)
- {
- QScopedPointer<QOffscreenSurface> surface(new QOffscreenSurface);
- surface->create();
- QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);
- ctx->create();
- ctx->makeCurrent(surface.get());
-
- auto wglGetExtensionsStringARB = reinterpret_cast<const char* (WINAPI* )(HDC)>
- (ctx->getProcAddress("wglGetExtensionsStringARB"));
- if (!wglGetExtensionsStringARB) {
- qCDebug(qLcEvrD3DPresentEngine) << "WGL extensions missing (no wglGetExtensionsStringARB function)";
- return false;
- }
-
- HWND hwnd = ::GetShellWindow();
- auto dc = ::GetDC(hwnd);
-
- const char *wglExtString = wglGetExtensionsStringARB(dc);
- if (!wglExtString)
- qCDebug(qLcEvrD3DPresentEngine) << "WGL extensions missing (wglGetExtensionsStringARB returned null)";
-
- bool hasExtension = wglExtString && strstr(wglExtString, "WGL_NV_DX_interop");
- ReleaseDC(hwnd, dc);
- if (!hasExtension) {
- qCDebug(qLcEvrD3DPresentEngine) << "WGL_NV_DX_interop missing";
- return false;
- }
-
- return getProc(ctx.get(), f.wglDXOpenDeviceNV, "wglDXOpenDeviceNV")
- && getProc(ctx.get(), f.wglDXCloseDeviceNV, "wglDXCloseDeviceNV")
- && getProc(ctx.get(), f.wglDXSetResourceShareHandleNV, "wglDXSetResourceShareHandleNV")
- && getProc(ctx.get(), f.wglDXRegisterObjectNV, "wglDXRegisterObjectNV")
- && getProc(ctx.get(), f.wglDXUnregisterObjectNV, "wglDXUnregisterObjectNV")
- && getProc(ctx.get(), f.wglDXLockObjectsNV, "wglDXLockObjectsNV")
- && getProc(ctx.get(), f.wglDXUnlockObjectsNV, "wglDXUnlockObjectsNV");
- }
- #endif
-
- namespace {
-
- bool hwTextureRenderingEnabled() {
- // add possibility for an user to opt-out HW video rendering
- // using the same env. variable as for FFmpeg backend
- static bool isDisableConversionSet = false;
- static const int disableHwConversion = qEnvironmentVariableIntValue(
- "QT_DISABLE_HW_TEXTURES_CONVERSION", &isDisableConversionSet);
-
- return !isDisableConversionSet || !disableHwConversion;
- }
-
- }
-
- HRESULT D3DPresentEngine::createD3DDevice()
- {
- if (!m_D3D9 || !m_devices)
- return MF_E_NOT_INITIALIZED;
-
- m_useTextureRendering = false;
- UINT adapterID = 0;
-
- if (hwTextureRenderingEnabled()) {
- QRhi *rhi = m_sink ? m_sink->rhi() : nullptr;
- if (rhi) {
- if (rhi->backend() == QRhi::D3D11) {
- m_useTextureRendering = findD3D11AdapterID(*rhi, m_D3D9.Get(), adapterID);
- #if QT_CONFIG(opengl)
- } else if (rhi->backend() == QRhi::OpenGLES2) {
- m_useTextureRendering = readWglNvDxInteropProc(m_wglNvDxInterop);
- #endif
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "Not supported RHI backend type";
- }
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "No RHI associated with this sink";
- }
-
- if (!m_useTextureRendering)
- qCDebug(qLcEvrD3DPresentEngine) << "Could not find compatible RHI adapter, zero copy disabled";
- }
-
- D3DCAPS9 ddCaps;
- ZeroMemory(&ddCaps, sizeof(ddCaps));
-
- HRESULT hr = m_D3D9->GetDeviceCaps(adapterID, D3DDEVTYPE_HAL, &ddCaps);
- if (FAILED(hr))
- return hr;
-
- DWORD vp = 0;
- if (ddCaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT)
- vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
- else
- vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
-
- D3DPRESENT_PARAMETERS pp;
- ZeroMemory(&pp, sizeof(pp));
-
- pp.BackBufferWidth = 1;
- pp.BackBufferHeight = 1;
- pp.BackBufferCount = 1;
- pp.Windowed = TRUE;
- pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
- pp.BackBufferFormat = D3DFMT_UNKNOWN;
- pp.hDeviceWindow = nullptr;
- pp.Flags = D3DPRESENTFLAG_VIDEO;
- pp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
-
- ComPtr<IDirect3DDevice9Ex> device;
-
- hr = m_D3D9->CreateDeviceEx(
- adapterID,
- D3DDEVTYPE_HAL,
- pp.hDeviceWindow,
- vp | D3DCREATE_NOWINDOWCHANGES | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,
- &pp,
- NULL,
- device.GetAddressOf()
- );
- if (FAILED(hr))
- return hr;
-
- hr = m_D3D9->GetAdapterDisplayMode(adapterID, &m_displayMode);
- if (FAILED(hr))
- return hr;
-
- hr = m_devices->ResetDevice(device.Get(), m_deviceResetToken);
- if (FAILED(hr))
- return hr;
-
- m_device = device;
- return hr;
- }
-
- bool D3DPresentEngine::isValid() const
- {
- return m_device.Get() != nullptr;
- }
-
- void D3DPresentEngine::releaseResources()
- {
- m_surfaceFormat = QVideoFrameFormat();
- }
-
- HRESULT D3DPresentEngine::getService(REFGUID, REFIID riid, void** ppv)
- {
- HRESULT hr = S_OK;
-
- if (riid == __uuidof(IDirect3DDeviceManager9)) {
- if (!m_devices) {
- hr = MF_E_UNSUPPORTED_SERVICE;
- } else {
- *ppv = m_devices.Get();
- m_devices->AddRef();
- }
- } else {
- hr = MF_E_UNSUPPORTED_SERVICE;
- }
-
- return hr;
- }
-
- HRESULT D3DPresentEngine::checkFormat(D3DFORMAT format)
- {
- if (!m_D3D9 || !m_device)
- return E_FAIL;
-
- HRESULT hr = S_OK;
-
- D3DDISPLAYMODE mode;
- D3DDEVICE_CREATION_PARAMETERS params;
-
- hr = m_device->GetCreationParameters(&params);
- if (FAILED(hr))
- return hr;
-
- UINT uAdapter = params.AdapterOrdinal;
- D3DDEVTYPE type = params.DeviceType;
-
- hr = m_D3D9->GetAdapterDisplayMode(uAdapter, &mode);
- if (FAILED(hr))
- return hr;
-
- hr = m_D3D9->CheckDeviceFormat(uAdapter, type, mode.Format,
- D3DUSAGE_RENDERTARGET,
- D3DRTYPE_SURFACE,
- format);
- if (FAILED(hr))
- return hr;
-
- bool ok = format == D3DFMT_X8R8G8B8
- || format == D3DFMT_A8R8G8B8
- || format == D3DFMT_X8B8G8R8
- || format == D3DFMT_A8B8G8R8;
-
- return ok ? S_OK : D3DERR_NOTAVAILABLE;
- }
-
- HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format,
- QList<ComPtr<IMFSample>> &videoSampleQueue,
- QSize frameSize)
- {
- if (!format || !m_device)
- return MF_E_UNEXPECTED;
-
- HRESULT hr = S_OK;
- releaseResources();
-
- UINT32 width = 0, height = 0;
- hr = MFGetAttributeSize(format, MF_MT_FRAME_SIZE, &width, &height);
- if (FAILED(hr))
- return hr;
-
- if (frameSize.isValid() && !frameSize.isEmpty()) {
- width = frameSize.width();
- height = frameSize.height();
- }
-
- DWORD d3dFormat = 0;
- hr = qt_evr_getFourCC(format, &d3dFormat);
- if (FAILED(hr))
- return hr;
-
- // FIXME: RHI defines only RGBA, thus add the alpha channel to the selected format
- if (d3dFormat == D3DFMT_X8R8G8B8)
- d3dFormat = D3DFMT_A8R8G8B8;
- else if (d3dFormat == D3DFMT_X8B8G8R8)
- d3dFormat = D3DFMT_A8B8G8R8;
-
- for (int i = 0; i < PRESENTER_BUFFER_COUNT; i++) {
- // texture ref cnt is increased by GetSurfaceLevel()/MFCreateVideoSampleFromSurface()
- // below, so it will be destroyed only when the sample pool is released.
- ComPtr<IDirect3DTexture9> texture;
- HANDLE sharedHandle = nullptr;
- hr = m_device->CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, (D3DFORMAT)d3dFormat, D3DPOOL_DEFAULT, texture.GetAddressOf(), &sharedHandle);
- if (FAILED(hr))
- break;
-
- ComPtr<IDirect3DSurface9> surface;
- hr = texture->GetSurfaceLevel(0, surface.GetAddressOf());
- if (FAILED(hr))
- break;
-
- ComPtr<IMFSample> videoSample;
- hr = MFCreateVideoSampleFromSurface(surface.Get(), videoSample.GetAddressOf());
- if (FAILED(hr))
- break;
-
- m_sampleTextureHandle[i] = {videoSample.Get(), sharedHandle};
- videoSampleQueue.append(videoSample);
- }
-
- std::optional<QVideoFrameFormat::ColorRange> colorRange =
- [&]() -> std::optional<QVideoFrameFormat::ColorRange> {
- MFNominalRange range;
- if (SUCCEEDED(format->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE,
- reinterpret_cast<UINT32 *>(&range)))) {
- qCDebug(qLcEvrD3DPresentEngine) << "MF_MT_VIDEO_NOMINAL_RANGE =" << range;
- switch (range) {
- case MFNominalRange::MFNominalRange_16_235:
- return QVideoFrameFormat::ColorRange::ColorRange_Video;
- case MFNominalRange::MFNominalRange_0_255:
- return QVideoFrameFormat::ColorRange::ColorRange_Full;
- default:
- break;
- }
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "MF_MT_VIDEO_NOMINAL_RANGE not set";
- }
- return std::nullopt;
- }();
-
- std::optional<QVideoFrameFormat::ColorTransfer> colorTransfer =
- [&]() -> std::optional<QVideoFrameFormat::ColorTransfer> {
- MFVideoTransferMatrix transferMatrix;
- if (SUCCEEDED(format->GetUINT32(MF_MT_YUV_MATRIX,
- reinterpret_cast<UINT32 *>(&transferMatrix)))) {
- qCDebug(qLcEvrD3DPresentEngine) << "MF_MT_YUV_MATRIX =" << transferMatrix;
-
- switch (transferMatrix) {
- case MFVideoTransferMatrix_BT709:
- return QVideoFrameFormat::ColorTransfer::ColorTransfer_BT709;
- case MFVideoTransferMatrix_BT601:
- return QVideoFrameFormat::ColorTransfer::ColorTransfer_BT601;
- case MFVideoTransferMatrix_SMPTE240M:
- return QVideoFrameFormat::ColorTransfer::ColorTransfer_BT709;
- case MFVideoTransferMatrix_BT2020_10:
- case MFVideoTransferMatrix_BT2020_12:
- return QVideoFrameFormat::ColorTransfer::ColorTransfer_ST2084;
- default:
- break;
- }
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "MF_MT_YUV_MATRIX not set";
- }
- return std::nullopt;
- }();
-
- std::optional<QVideoFrameFormat::ColorSpace> colorSpace =
- [&]() -> std::optional<QVideoFrameFormat::ColorSpace> {
- MFVideoPrimaries primaries;
- if (SUCCEEDED(format->GetUINT32(MF_MT_VIDEO_PRIMARIES,
- reinterpret_cast<UINT32 *>(&primaries)))) {
- qCDebug(qLcEvrD3DPresentEngine) << "MFVideoPrimaries =" << primaries;
-
- switch (primaries) {
- case MFVideoPrimaries_BT709:
- return QVideoFrameFormat::ColorSpace::ColorSpace_BT709;
- case MFVideoPrimaries_BT470_2_SysM:
- case MFVideoPrimaries_BT470_2_SysBG:
- case MFVideoPrimaries_SMPTE170M:
- case MFVideoPrimaries_EBU3213:
- case MFVideoPrimaries_SMPTE_C:
- return QVideoFrameFormat::ColorSpace::ColorSpace_BT601;
-
- case MFVideoPrimaries_SMPTE240M:
- return QVideoFrameFormat::ColorSpace::ColorSpace_BT709;
- case MFVideoPrimaries_BT2020:
- return QVideoFrameFormat::ColorSpace::ColorSpace_BT2020;
- case MFVideoPrimaries_DCI_P3:
- return QVideoFrameFormat::ColorSpace::ColorSpace_BT2020;
- case MFVideoPrimaries_XYZ:
- case MFVideoPrimaries_ACES:
- return QVideoFrameFormat::ColorSpace::ColorSpace_Undefined;
- default:
- return QVideoFrameFormat::ColorSpace::ColorSpace_Undefined;
- }
- } else {
- qCDebug(qLcEvrD3DPresentEngine) << "MF_MT_YUV_MATRIX not set";
- }
- return std::nullopt;
- }();
-
- if (SUCCEEDED(hr)) {
- m_surfaceFormat = QVideoFrameFormat(QSize(width, height), qt_evr_pixelFormatFromD3DFormat(d3dFormat));
- if (colorRange)
- m_surfaceFormat.setColorRange(*colorRange);
- if (colorTransfer)
- m_surfaceFormat.setColorTransfer(*colorTransfer);
- if (colorSpace)
- m_surfaceFormat.setColorSpace(*colorSpace);
- } else {
- releaseResources();
- }
-
- return hr;
- }
-
- QVideoFrame D3DPresentEngine::makeVideoFrame(const ComPtr<IMFSample> &sample,
- QtVideo::Rotation rotation)
- {
- if (!sample)
- return {};
-
- HANDLE sharedHandle = nullptr;
- for (const auto &p : m_sampleTextureHandle)
- if (p.first == sample.Get())
- sharedHandle = p.second;
-
- std::unique_ptr<IMFSampleVideoBuffer> vb;
- QRhi *rhi = m_sink ? m_sink->rhi() : nullptr;
- if (m_useTextureRendering && sharedHandle && rhi) {
- if (rhi->backend() == QRhi::D3D11) {
- vb = std::make_unique<D3D11TextureVideoBuffer>(m_device, sample, sharedHandle);
- #if QT_CONFIG(opengl)
- } else if (rhi->backend() == QRhi::OpenGLES2) {
- vb = std::make_unique<OpenGlVideoBuffer>(m_device, sample, m_wglNvDxInterop,
- sharedHandle);
- #endif
- }
- }
-
- if (!vb)
- vb = std::make_unique<IMFSampleVideoBuffer>(m_device, sample);
-
- auto format = m_surfaceFormat;
- format.setRotation(rotation);
- QVideoFrame frame = QVideoFramePrivate::createFrame(std::move(vb), format);
-
- // WMF uses 100-nanosecond units, Qt uses microseconds
- LONGLONG startTime = 0;
- auto hr = sample->GetSampleTime(&startTime);
- if (SUCCEEDED(hr)) {
- frame.setStartTime(startTime / 10);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(sample->GetSampleDuration(&duration)))
- frame.setEndTime((startTime + duration) / 10);
- }
-
- return frame;
- }
-
- QT_END_NAMESPACE