Revision control
Copy as Markdown
// Copyright (C) 2025 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
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists for the convenience
// of other Qt classes. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qwmf_support_p.h"
#include <mferror.h>
QT_BEGIN_NAMESPACE
namespace QWMF {
HRESULT QByteArrayMFMediaBuffer::CreateInstance(QByteArray data, IMFMediaBuffer **ppBuffer,
bool isReadOnly)
{
if (!ppBuffer)
return E_POINTER;
DWORD size = data.size();
QByteArrayMFMediaBuffer *pBuffer =
new (std::nothrow) QByteArrayMFMediaBuffer(std::move(data), isReadOnly);
if (!pBuffer)
return E_OUTOFMEMORY;
pBuffer->SetCurrentLength(size);
HRESULT hr =
pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
pBuffer->Release();
return hr;
}
HRESULT QByteArrayMFMediaBuffer::CreateInstance(qsizetype capacity, IMFMediaBuffer **ppBuffer)
{
if (!ppBuffer)
return E_POINTER;
QByteArray buffer{ capacity, Qt::Initialization::Uninitialized };
QByteArrayMFMediaBuffer *pBuffer =
new (std::nothrow) QByteArrayMFMediaBuffer(std::move(buffer), /*isReadOnly=*/false);
if (!pBuffer)
return E_OUTOFMEMORY;
HRESULT hr =
pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
pBuffer->Release();
return hr;
}
HRESULT QByteArrayMFMediaBuffer::Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength,
DWORD *pcbCurrentLength)
{
if (!ppbBuffer)
return E_POINTER;
if (m_isLocked.test_and_set(std::memory_order_acquire))
return MF_E_INVALIDREQUEST; // Buffer is already locked.
if (m_isReadOnly)
// we assume that the IMFTransform is not working in-place, so we can avoid `detach` here
*ppbBuffer = const_cast<BYTE *>(reinterpret_cast<const BYTE *>(m_byteArray.constData()));
else
*ppbBuffer = reinterpret_cast<BYTE *>(m_byteArray.data());
if (pcbMaxLength)
*pcbMaxLength = GetMaxLengthInternal();
if (pcbCurrentLength)
*pcbCurrentLength = m_currentLength;
return S_OK;
}
HRESULT QByteArrayMFMediaBuffer::Unlock()
{
m_isLocked.clear(std::memory_order_release);
return S_OK;
}
HRESULT QByteArrayMFMediaBuffer::GetCurrentLength(DWORD *pcbCurrentLength)
{
if (!pcbCurrentLength)
return E_POINTER;
*pcbCurrentLength = m_currentLength;
return S_OK;
}
HRESULT QByteArrayMFMediaBuffer::SetCurrentLength(DWORD cbCurrentLength)
{
if (cbCurrentLength > GetMaxLengthInternal())
return E_INVALIDARG;
m_currentLength = cbCurrentLength;
return S_OK;
}
HRESULT QByteArrayMFMediaBuffer::GetMaxLength(DWORD *pcbMaxLength)
{
if (!pcbMaxLength)
return E_POINTER;
*pcbMaxLength = GetMaxLengthInternal();
return S_OK;
}
QByteArrayMFMediaBuffer::QByteArrayMFMediaBuffer(QByteArray &&data, bool isReadOnly)
: m_byteArray(std::move(data)), m_isReadOnly(isReadOnly)
{
}
DWORD QByteArrayMFMediaBuffer::GetMaxLengthInternal() const
{
return static_cast<DWORD>(m_byteArray.size());
}
QByteArray QByteArrayMFMediaBuffer::takeByteArray()
{
return std::move(m_byteArray);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
HRESULT QPmrMediaBuffer::CreateInstance(QSpan<const std::byte> data,
std::pmr::memory_resource *resource,
IMFMediaBuffer **ppBuffer)
{
if (!ppBuffer || !resource)
return E_POINTER;
*ppBuffer = nullptr;
auto *buffer = resource->allocate(sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
if (!buffer)
return E_OUTOFMEMORY;
QPmrMediaBuffer *pBuffer = new (buffer) QPmrMediaBuffer(data, resource);
HRESULT hr =
pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
pBuffer->Release();
return hr;
}
HRESULT QPmrMediaBuffer::CreateInstance(qsizetype capacity, std::pmr::memory_resource *resource,
IMFMediaBuffer **ppBuffer)
{
if (!ppBuffer || !resource)
return E_POINTER;
*ppBuffer = nullptr;
void *buffer = resource->allocate(sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
QPmrMediaBuffer *pBuffer = new (buffer) QPmrMediaBuffer(capacity, resource);
if (!pBuffer)
return E_OUTOFMEMORY;
HRESULT hr =
pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
pBuffer->Release();
return hr;
}
ULONG QPmrMediaBuffer::Release()
{
const LONG referenceCount = m_referenceCount.fetch_sub(1, std::memory_order_release) - 1;
if (referenceCount == 0) {
// This acquire fence synchronizes with the release operation in other threads.
// It ensures that all memory writes made to this object by other threads
// are visible to this thread before we proceed to delete it.
std::atomic_thread_fence(std::memory_order_acquire);
std::pmr::memory_resource *resource = m_memoryResource;
this->~QPmrMediaBuffer();
resource->deallocate(this, sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
}
return referenceCount;
}
STDMETHODIMP QPmrMediaBuffer::Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength)
{
if (!ppbBuffer)
return E_POINTER;
if (m_isLocked.test_and_set(std::memory_order_acquire))
return MF_E_INVALIDREQUEST;
*ppbBuffer = reinterpret_cast<BYTE *>(m_buffer);
if (pcbMaxLength)
*pcbMaxLength = m_maxLength;
if (pcbCurrentLength)
*pcbCurrentLength = m_currentLength;
return S_OK;
}
STDMETHODIMP QPmrMediaBuffer::Unlock()
{
m_isLocked.clear(std::memory_order_release);
return S_OK;
}
STDMETHODIMP QPmrMediaBuffer::GetCurrentLength(DWORD *pcbCurrentLength)
{
if (!pcbCurrentLength)
return E_POINTER;
*pcbCurrentLength = m_currentLength;
return S_OK;
}
STDMETHODIMP QPmrMediaBuffer::SetCurrentLength(DWORD cbCurrentLength)
{
if (cbCurrentLength > m_maxLength)
return E_INVALIDARG;
m_currentLength = cbCurrentLength;
return S_OK;
}
STDMETHODIMP QPmrMediaBuffer::GetMaxLength(DWORD *pcbMaxLength)
{
if (!pcbMaxLength)
return E_POINTER;
*pcbMaxLength = m_maxLength;
return S_OK;
}
static constexpr auto mfBufferAlignment = 16;
QPmrMediaBuffer::QPmrMediaBuffer(QSpan<const std::byte> data, std::pmr::memory_resource *resource)
: QPmrMediaBuffer(data.size(), resource)
{
m_currentLength = data.size(), std::copy(data.begin(), data.end(), m_buffer);
}
QPmrMediaBuffer::QPmrMediaBuffer(qsizetype capacity, std::pmr::memory_resource *resource)
: m_memoryResource(resource),
m_maxLength(DWORD(capacity)),
m_buffer(static_cast<std::byte *>(resource->allocate(capacity, mfBufferAlignment)))
{
}
QPmrMediaBuffer::~QPmrMediaBuffer()
{
m_memoryResource->deallocate(m_buffer, m_maxLength, mfBufferAlignment);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace QWMF
QT_END_NAMESPACE