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
mfstream.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
4#include "mfstream_p.h"
5#include <QtCore/qcoreapplication.h>
6
8//MFStream is added for supporting QIODevice type of media source.
9//It is used to delegate invocations from media foundation(through IMFByteStream) to QIODevice.
10
11MFStream::MFStream(QIODevice *stream, bool ownStream)
12 : m_cRef(1)
13 , m_stream(stream)
14 , m_ownStream(ownStream)
15 , m_currentReadResult(0)
16{
17 //Move to the thread of the stream object
18 //to make sure invocations on stream
19 //are happened in the same thread of stream object
20 this->moveToThread(stream->thread());
21}
22
23MFStream::~MFStream()
24{
25 if (m_currentReadResult)
26 m_currentReadResult->Release();
27 if (m_ownStream)
28 m_stream->deleteLater();
29}
30
31//from IUnknown
32STDMETHODIMP MFStream::QueryInterface(REFIID riid, LPVOID *ppvObject)
33{
34 if (!ppvObject)
35 return E_POINTER;
36 if (riid == IID_IMFByteStream) {
37 *ppvObject = static_cast<IMFByteStream*>(this);
38 } else if (riid == IID_IUnknown) {
39 *ppvObject = static_cast<IUnknown*>(this);
40 } else {
41 *ppvObject = NULL;
42 return E_NOINTERFACE;
43 }
44 AddRef();
45 return S_OK;
46}
47
48STDMETHODIMP_(ULONG) MFStream::AddRef(void)
49{
50 return InterlockedIncrement(&m_cRef);
51}
52
53STDMETHODIMP_(ULONG) MFStream::Release(void)
54{
55 LONG cRef = InterlockedDecrement(&m_cRef);
56 if (cRef == 0) {
57 this->deleteLater();
58 }
59 return cRef;
60}
61
62
63//from IMFByteStream
64STDMETHODIMP MFStream::GetCapabilities(DWORD *pdwCapabilities)
65{
66 if (!pdwCapabilities)
67 return E_INVALIDARG;
68 *pdwCapabilities = MFBYTESTREAM_IS_READABLE;
69 if (!m_stream->isSequential())
70 *pdwCapabilities |= MFBYTESTREAM_IS_SEEKABLE;
71 return S_OK;
72}
73
74STDMETHODIMP MFStream::GetLength(QWORD *pqwLength)
75{
76 if (!pqwLength)
77 return E_INVALIDARG;
78 QMutexLocker locker(&m_mutex);
79 *pqwLength = QWORD(m_stream->size());
80 return S_OK;
81}
82
83STDMETHODIMP MFStream::SetLength(QWORD)
84{
85 return E_NOTIMPL;
86}
87
88STDMETHODIMP MFStream::GetCurrentPosition(QWORD *pqwPosition)
89{
90 if (!pqwPosition)
91 return E_INVALIDARG;
92 QMutexLocker locker(&m_mutex);
93 *pqwPosition = m_stream->pos();
94 return S_OK;
95}
96
97STDMETHODIMP MFStream::SetCurrentPosition(QWORD qwPosition)
98{
99 QMutexLocker locker(&m_mutex);
100 //SetCurrentPosition may happend during the BeginRead/EndRead pair,
101 //refusing to execute SetCurrentPosition during that time seems to be
102 //the simplest workable solution
103 if (m_currentReadResult)
104 return S_FALSE;
105
106 bool seekOK = m_stream->seek(qint64(qwPosition));
107 if (seekOK)
108 return S_OK;
109 else
110 return S_FALSE;
111}
112
113STDMETHODIMP MFStream::IsEndOfStream(BOOL *pfEndOfStream)
114{
115 if (!pfEndOfStream)
116 return E_INVALIDARG;
117 QMutexLocker locker(&m_mutex);
118 *pfEndOfStream = m_stream->atEnd() ? TRUE : FALSE;
119 return S_OK;
120}
121
122STDMETHODIMP MFStream::Read(BYTE *pb, ULONG cb, ULONG *pcbRead)
123{
124 QMutexLocker locker(&m_mutex);
125 qint64 read = m_stream->read((char*)(pb), qint64(cb));
126 if (pcbRead)
127 *pcbRead = ULONG(read);
128 return S_OK;
129}
130
131STDMETHODIMP MFStream::BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
132 IUnknown *punkState)
133{
134 if (!pCallback || !pb)
135 return E_INVALIDARG;
136
137 Q_ASSERT(m_currentReadResult == NULL);
138
139 AsyncReadState *state = new (std::nothrow) AsyncReadState(pb, cb);
140 if (state == NULL)
141 return E_OUTOFMEMORY;
142
143 HRESULT hr = MFCreateAsyncResult(state, pCallback, punkState, &m_currentReadResult);
144 state->Release();
145 if (FAILED(hr))
146 return hr;
147
148 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
149 return hr;
150}
151
152STDMETHODIMP MFStream::EndRead(IMFAsyncResult* pResult, ULONG *pcbRead)
153{
154 if (!pcbRead)
155 return E_INVALIDARG;
156 IUnknown *pUnk;
157 pResult->GetObject(&pUnk);
158 AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
159 *pcbRead = state->bytesRead();
160 pUnk->Release();
161
162 m_currentReadResult->Release();
163 m_currentReadResult = NULL;
164
165 return S_OK;
166}
167
168STDMETHODIMP MFStream::Write(const BYTE *, ULONG, ULONG *)
169{
170 return E_NOTIMPL;
171}
172
173STDMETHODIMP MFStream::BeginWrite(const BYTE *, ULONG ,
174 IMFAsyncCallback *,
175 IUnknown *)
176{
177 return E_NOTIMPL;
178}
179
180STDMETHODIMP MFStream::EndWrite(IMFAsyncResult *,
181 ULONG *)
182{
183 return E_NOTIMPL;
184}
185
186STDMETHODIMP MFStream::Seek(
187 MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
188 LONGLONG llSeekOffset,
189 DWORD,
190 QWORD *pqwCurrentPosition)
191{
192 QMutexLocker locker(&m_mutex);
193 if (m_currentReadResult)
194 return S_FALSE;
195
196 qint64 pos = qint64(llSeekOffset);
197 switch (SeekOrigin) {
198 case msoBegin:
199 break;
200 case msoCurrent:
201 pos += m_stream->pos();
202 break;
203 }
204 bool seekOK = m_stream->seek(pos);
205 if (pqwCurrentPosition)
206 *pqwCurrentPosition = pos;
207 if (seekOK)
208 return S_OK;
209 else
210 return S_FALSE;
211}
212
213STDMETHODIMP MFStream::Flush()
214{
215 return E_NOTIMPL;
216}
217
218STDMETHODIMP MFStream::Close()
219{
220 QMutexLocker locker(&m_mutex);
221 if (m_ownStream)
222 m_stream->close();
223 return S_OK;
224}
225
226void MFStream::doRead()
227{
228 if (!m_stream)
229 return;
230
231 bool readDone = true;
232 IUnknown *pUnk = NULL;
233 HRESULT hr = m_currentReadResult->GetObject(&pUnk);
234 if (SUCCEEDED(hr)) {
235 //do actual read
236 AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
237 ULONG cbRead;
238 Read(state->pb(), state->cb() - state->bytesRead(), &cbRead);
239 pUnk->Release();
240
241 state->setBytesRead(cbRead + state->bytesRead());
242 if (state->cb() > state->bytesRead() && !m_stream->atEnd()) {
243 readDone = false;
244 }
245 }
246
247 if (readDone) {
248 //now inform the original caller
249 m_currentReadResult->SetStatus(hr);
250 MFInvokeCallback(m_currentReadResult);
251 }
252}
253
254void MFStream::customEvent(QEvent *event)
255{
256 if (event->type() != QEvent::User) {
257 QObject::customEvent(event);
258 return;
259 }
260 doRead();
261}
262
263//AsyncReadState is a helper class used in BeginRead for asynchronous operation
264//to record some BeginRead parameters, so these parameters could be
265//used later when actually executing the read operation in another thread.
266MFStream::AsyncReadState::AsyncReadState(BYTE *pb, ULONG cb)
267 : m_cRef(1)
268 , m_pb(pb)
269 , m_cb(cb)
270 , m_cbRead(0)
271{
272}
273
274//from IUnknown
275STDMETHODIMP MFStream::AsyncReadState::QueryInterface(REFIID riid, LPVOID *ppvObject)
276{
277 if (!ppvObject)
278 return E_POINTER;
279
280 if (riid == IID_IUnknown) {
281 *ppvObject = static_cast<IUnknown*>(this);
282 } else {
283 *ppvObject = NULL;
284 return E_NOINTERFACE;
285 }
286 AddRef();
287 return S_OK;
288}
289
290STDMETHODIMP_(ULONG) MFStream::AsyncReadState::AddRef(void)
291{
292 return InterlockedIncrement(&m_cRef);
293}
294
295STDMETHODIMP_(ULONG) MFStream::AsyncReadState::Release(void)
296{
297 LONG cRef = InterlockedDecrement(&m_cRef);
298 if (cRef == 0)
299 delete this;
300 // For thread safety, return a temporary variable.
301 return cRef;
302}
303
304BYTE* MFStream::AsyncReadState::pb() const
305{
306 return m_pb;
307}
308
309ULONG MFStream::AsyncReadState::cb() const
310{
311 return m_cb;
312}
313
314ULONG MFStream::AsyncReadState::bytesRead() const
315{
316 return m_cbRead;
317}
318
319void MFStream::AsyncReadState::setBytesRead(ULONG cbRead)
320{
321 m_cbRead = cbRead;
322}
323
324QT_END_NAMESPACE
325
326#include "moc_mfstream_p.cpp"
\inmodule QtCore \reentrant
Definition qiodevice.h:38
STDMETHODIMP_(ULONG) QWindowsMediaDeviceReader