Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwmf_support.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 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
4//
5// W A R N I N G
6// -------------
7//
8// This file is not part of the Qt API. It exists for the convenience
9// of other Qt classes. This header file may change from version to
10// version without notice, or even be removed.
11//
12// We mean it.
13//
14
15#include "qwmf_support_p.h"
16
17#include <mferror.h>
18
20
21namespace QWMF {
22
23HRESULT QByteArrayMFMediaBuffer::CreateInstance(QByteArray data, IMFMediaBuffer **ppBuffer,
24 bool isReadOnly)
25{
26 if (!ppBuffer)
27 return E_POINTER;
28
29 DWORD size = data.size();
30
31 QByteArrayMFMediaBuffer *pBuffer =
32 new (std::nothrow) QByteArrayMFMediaBuffer(std::move(data), isReadOnly);
33 if (!pBuffer)
34 return E_OUTOFMEMORY;
35
36 pBuffer->SetCurrentLength(size);
37
38 HRESULT hr =
39 pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
40
41 pBuffer->Release();
42 return hr;
43}
44
45HRESULT QByteArrayMFMediaBuffer::CreateInstance(qsizetype capacity, IMFMediaBuffer **ppBuffer)
46{
47 if (!ppBuffer)
48 return E_POINTER;
49
50 QByteArray buffer{ capacity, Qt::Initialization::Uninitialized };
51 QByteArrayMFMediaBuffer *pBuffer =
52 new (std::nothrow) QByteArrayMFMediaBuffer(std::move(buffer), /*isReadOnly=*/false);
53 if (!pBuffer)
54 return E_OUTOFMEMORY;
55
56 HRESULT hr =
57 pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
58
59 pBuffer->Release();
60 return hr;
61}
62
63HRESULT QByteArrayMFMediaBuffer::Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength,
64 DWORD *pcbCurrentLength)
65{
66 if (!ppbBuffer)
67 return E_POINTER;
68
69 if (m_isLocked.test_and_set(std::memory_order_acquire))
70 return MF_E_INVALIDREQUEST; // Buffer is already locked.
71
72 if (m_isReadOnly)
73 // we assume that the IMFTransform is not working in-place, so we can avoid `detach` here
74 *ppbBuffer = const_cast<BYTE *>(reinterpret_cast<const BYTE *>(m_byteArray.constData()));
75 else
76 *ppbBuffer = reinterpret_cast<BYTE *>(m_byteArray.data());
77
78 if (pcbMaxLength)
79 *pcbMaxLength = GetMaxLengthInternal();
80
81 if (pcbCurrentLength)
82 *pcbCurrentLength = m_currentLength;
83
84 return S_OK;
85}
86
87HRESULT QByteArrayMFMediaBuffer::Unlock()
88{
89 m_isLocked.clear(std::memory_order_release);
90 return S_OK;
91}
92
93HRESULT QByteArrayMFMediaBuffer::GetCurrentLength(DWORD *pcbCurrentLength)
94{
95 if (!pcbCurrentLength)
96 return E_POINTER;
97
98 *pcbCurrentLength = m_currentLength;
99 return S_OK;
100}
101
102HRESULT QByteArrayMFMediaBuffer::SetCurrentLength(DWORD cbCurrentLength)
103{
104 if (cbCurrentLength > GetMaxLengthInternal())
105 return E_INVALIDARG;
106
107 m_currentLength = cbCurrentLength;
108 return S_OK;
109}
110
111HRESULT QByteArrayMFMediaBuffer::GetMaxLength(DWORD *pcbMaxLength)
112{
113 if (!pcbMaxLength)
114 return E_POINTER;
115
116 *pcbMaxLength = GetMaxLengthInternal();
117 return S_OK;
118}
119
120QByteArrayMFMediaBuffer::QByteArrayMFMediaBuffer(QByteArray &&data, bool isReadOnly)
121 : m_byteArray(std::move(data)), m_isReadOnly(isReadOnly)
122{
123}
124
125DWORD QByteArrayMFMediaBuffer::GetMaxLengthInternal() const
126{
127 return static_cast<DWORD>(m_byteArray.size());
128}
129
130QByteArray QByteArrayMFMediaBuffer::takeByteArray()
131{
132 return std::move(m_byteArray);
133}
134
135///////////////////////////////////////////////////////////////////////////////////////////////////
136
137HRESULT QPmrMediaBuffer::CreateInstance(QSpan<const std::byte> data,
140{
141 if (!ppBuffer || !resource)
142 return E_POINTER;
143
144 *ppBuffer = nullptr;
145
146 auto *buffer = resource->allocate(sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
147 if (!buffer)
148 return E_OUTOFMEMORY;
149
151
152 HRESULT hr =
153 pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
154
155 pBuffer->Release();
156
157 return hr;
158}
159
160HRESULT QPmrMediaBuffer::CreateInstance(qsizetype capacity, std::pmr::memory_resource *resource,
161 IMFMediaBuffer **ppBuffer)
162{
163 if (!ppBuffer || !resource)
164 return E_POINTER;
165
166 *ppBuffer = nullptr;
167 void *buffer = resource->allocate(sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
168 QPmrMediaBuffer *pBuffer = new (buffer) QPmrMediaBuffer(capacity, resource);
169 if (!pBuffer)
170 return E_OUTOFMEMORY;
171
172 HRESULT hr =
173 pBuffer->QueryInterface(__uuidof(IMFMediaBuffer), reinterpret_cast<void **>(ppBuffer));
174 pBuffer->Release();
175 return hr;
176}
177
178ULONG QPmrMediaBuffer::Release()
179{
180 const LONG referenceCount = m_referenceCount.fetch_sub(1, std::memory_order_release) - 1;
181 if (referenceCount == 0) {
182 // This acquire fence synchronizes with the release operation in other threads.
183 // It ensures that all memory writes made to this object by other threads
184 // are visible to this thread before we proceed to delete it.
185 std::atomic_thread_fence(std::memory_order_acquire);
186
187 std::pmr::memory_resource *resource = m_memoryResource;
188
189 this->~QPmrMediaBuffer();
190 resource->deallocate(this, sizeof(QPmrMediaBuffer), alignof(QPmrMediaBuffer));
191 }
192
193 return referenceCount;
194}
195
196STDMETHODIMP QPmrMediaBuffer::Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength)
197{
198 if (!ppbBuffer)
199 return E_POINTER;
200
201 if (m_isLocked.test_and_set(std::memory_order_acquire))
202 return MF_E_INVALIDREQUEST;
203
204 *ppbBuffer = reinterpret_cast<BYTE *>(m_buffer);
205
206 if (pcbMaxLength)
207 *pcbMaxLength = m_maxLength;
208
209 if (pcbCurrentLength)
210 *pcbCurrentLength = m_currentLength;
211
212 return S_OK;
213}
214
215STDMETHODIMP QPmrMediaBuffer::Unlock()
216{
217 m_isLocked.clear(std::memory_order_release);
218 return S_OK;
219}
220
221STDMETHODIMP QPmrMediaBuffer::GetCurrentLength(DWORD *pcbCurrentLength)
222{
223 if (!pcbCurrentLength)
224 return E_POINTER;
225
226 *pcbCurrentLength = m_currentLength;
227 return S_OK;
228}
229
230STDMETHODIMP QPmrMediaBuffer::SetCurrentLength(DWORD cbCurrentLength)
231{
232 if (cbCurrentLength > m_maxLength)
233 return E_INVALIDARG;
234
235 m_currentLength = cbCurrentLength;
236 return S_OK;
237}
238
239STDMETHODIMP QPmrMediaBuffer::GetMaxLength(DWORD *pcbMaxLength)
240{
241 if (!pcbMaxLength)
242 return E_POINTER;
243
244 *pcbMaxLength = m_maxLength;
245 return S_OK;
246}
247
248static constexpr auto mfBufferAlignment = 16;
249
250QPmrMediaBuffer::QPmrMediaBuffer(QSpan<const std::byte> data, std::pmr::memory_resource *resource)
251 : QPmrMediaBuffer(data.size(), resource)
252{
253 m_currentLength = data.size(), std::copy(data.begin(), data.end(), m_buffer);
254}
255
256QPmrMediaBuffer::QPmrMediaBuffer(qsizetype capacity, std::pmr::memory_resource *resource)
257 : m_memoryResource(resource),
258 m_maxLength(DWORD(capacity)),
259 m_buffer(static_cast<std::byte *>(resource->allocate(capacity, mfBufferAlignment)))
260{
261}
262
263QPmrMediaBuffer::~QPmrMediaBuffer()
264{
265 m_memoryResource->deallocate(m_buffer, m_maxLength, mfBufferAlignment);
266}
267
268///////////////////////////////////////////////////////////////////////////////////////////////////
269
270} // namespace QWMF
271
272QT_END_NAMESPACE
STDMETHODIMP GetCurrentLength(DWORD *pcbCurrentLength) override
STDMETHODIMP Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength) override
STDMETHODIMP SetCurrentLength(DWORD cbCurrentLength) override
STDMETHODIMP Unlock() override
STDMETHODIMP GetMaxLength(DWORD *pcbMaxLength) override
STDMETHODIMP Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength) override
STDMETHODIMP SetCurrentLength(DWORD cbCurrentLength) override
STDMETHODIMP GetCurrentLength(DWORD *pcbCurrentLength) override
STDMETHODIMP GetMaxLength(DWORD *pcbMaxLength) override
STDMETHODIMP Unlock() override
static constexpr auto mfBufferAlignment