Warning: That file was not part of the compilation database. It may have many parsing errors.

1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Mobility Components.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "mfstream.h"
41#include <QtCore/qcoreapplication.h>
42
43//MFStream is added for supporting QIODevice type of media source.
44//It is used to delegate invocations from media foundation(through IMFByteStream) to QIODevice.
45
46MFStream::MFStream(QIODevice *stream, bool ownStream)
47 : m_cRef(1)
48 , m_stream(stream)
49 , m_ownStream(ownStream)
50 , m_currentReadResult(0)
51{
52 //Move to the thread of the stream object
53 //to make sure invocations on stream
54 //are happened in the same thread of stream object
55 this->moveToThread(stream->thread());
56 connect(stream, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
57}
58
59MFStream::~MFStream()
60{
61 if (m_currentReadResult)
62 m_currentReadResult->Release();
63 if (m_ownStream)
64 m_stream->deleteLater();
65}
66
67//from IUnknown
68STDMETHODIMP MFStream::QueryInterface(REFIID riid, LPVOID *ppvObject)
69{
70 if (!ppvObject)
71 return E_POINTER;
72 if (riid == IID_IMFByteStream) {
73 *ppvObject = static_cast<IMFByteStream*>(this);
74 } else if (riid == IID_IUnknown) {
75 *ppvObject = static_cast<IUnknown*>(this);
76 } else {
77 *ppvObject = NULL;
78 return E_NOINTERFACE;
79 }
80 AddRef();
81 return S_OK;
82}
83
84STDMETHODIMP_(ULONG) MFStream::AddRef(void)
85{
86 return InterlockedIncrement(&m_cRef);
87}
88
89STDMETHODIMP_(ULONG) MFStream::Release(void)
90{
91 LONG cRef = InterlockedDecrement(&m_cRef);
92 if (cRef == 0) {
93 this->deleteLater();
94 }
95 return cRef;
96}
97
98
99//from IMFByteStream
100STDMETHODIMP MFStream::GetCapabilities(DWORD *pdwCapabilities)
101{
102 if (!pdwCapabilities)
103 return E_INVALIDARG;
104 *pdwCapabilities = MFBYTESTREAM_IS_READABLE;
105 if (!m_stream->isSequential())
106 *pdwCapabilities |= MFBYTESTREAM_IS_SEEKABLE;
107 return S_OK;
108}
109
110STDMETHODIMP MFStream::GetLength(QWORD *pqwLength)
111{
112 if (!pqwLength)
113 return E_INVALIDARG;
114 QMutexLocker locker(&m_mutex);
115 *pqwLength = QWORD(m_stream->size());
116 return S_OK;
117}
118
119STDMETHODIMP MFStream::SetLength(QWORD)
120{
121 return E_NOTIMPL;
122}
123
124STDMETHODIMP MFStream::GetCurrentPosition(QWORD *pqwPosition)
125{
126 if (!pqwPosition)
127 return E_INVALIDARG;
128 QMutexLocker locker(&m_mutex);
129 *pqwPosition = m_stream->pos();
130 return S_OK;
131}
132
133STDMETHODIMP MFStream::SetCurrentPosition(QWORD qwPosition)
134{
135 QMutexLocker locker(&m_mutex);
136 //SetCurrentPosition may happend during the BeginRead/EndRead pair,
137 //refusing to execute SetCurrentPosition during that time seems to be
138 //the simplest workable solution
139 if (m_currentReadResult)
140 return S_FALSE;
141
142 bool seekOK = m_stream->seek(qint64(qwPosition));
143 if (seekOK)
144 return S_OK;
145 else
146 return S_FALSE;
147}
148
149STDMETHODIMP MFStream::IsEndOfStream(BOOL *pfEndOfStream)
150{
151 if (!pfEndOfStream)
152 return E_INVALIDARG;
153 QMutexLocker locker(&m_mutex);
154 *pfEndOfStream = m_stream->atEnd() ? TRUE : FALSE;
155 return S_OK;
156}
157
158STDMETHODIMP MFStream::Read(BYTE *pb, ULONG cb, ULONG *pcbRead)
159{
160 QMutexLocker locker(&m_mutex);
161 qint64 read = m_stream->read((char*)(pb), qint64(cb));
162 if (pcbRead)
163 *pcbRead = ULONG(read);
164 return S_OK;
165}
166
167STDMETHODIMP MFStream::BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
168 IUnknown *punkState)
169{
170 if (!pCallback || !pb)
171 return E_INVALIDARG;
172
173 Q_ASSERT(m_currentReadResult == NULL);
174
175 AsyncReadState *state = new (std::nothrow) AsyncReadState(pb, cb);
176 if (state == NULL)
177 return E_OUTOFMEMORY;
178
179 HRESULT hr = MFCreateAsyncResult(state, pCallback, punkState, &m_currentReadResult);
180 state->Release();
181 if (FAILED(hr))
182 return hr;
183
184 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
185 return hr;
186}
187
188STDMETHODIMP MFStream::EndRead(IMFAsyncResult* pResult, ULONG *pcbRead)
189{
190 if (!pcbRead)
191 return E_INVALIDARG;
192 IUnknown *pUnk;
193 pResult->GetObject(&pUnk);
194 AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
195 *pcbRead = state->bytesRead();
196 pUnk->Release();
197
198 m_currentReadResult->Release();
199 m_currentReadResult = NULL;
200
201 return S_OK;
202}
203
204STDMETHODIMP MFStream::Write(const BYTE *, ULONG, ULONG *)
205{
206 return E_NOTIMPL;
207}
208
209STDMETHODIMP MFStream::BeginWrite(const BYTE *, ULONG ,
210 IMFAsyncCallback *,
211 IUnknown *)
212{
213 return E_NOTIMPL;
214}
215
216STDMETHODIMP MFStream::EndWrite(IMFAsyncResult *,
217 ULONG *)
218{
219 return E_NOTIMPL;
220}
221
222STDMETHODIMP MFStream::Seek(
223 MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
224 LONGLONG llSeekOffset,
225 DWORD,
226 QWORD *pqwCurrentPosition)
227{
228 QMutexLocker locker(&m_mutex);
229 if (m_currentReadResult)
230 return S_FALSE;
231
232 qint64 pos = qint64(llSeekOffset);
233 switch (SeekOrigin) {
234 case msoBegin:
235 break;
236 case msoCurrent:
237 pos += m_stream->pos();
238 break;
239 }
240 bool seekOK = m_stream->seek(pos);
241 if (pqwCurrentPosition)
242 *pqwCurrentPosition = pos;
243 if (seekOK)
244 return S_OK;
245 else
246 return S_FALSE;
247}
248
249STDMETHODIMP MFStream::Flush()
250{
251 return E_NOTIMPL;
252}
253
254STDMETHODIMP MFStream::Close()
255{
256 QMutexLocker locker(&m_mutex);
257 if (m_ownStream)
258 m_stream->close();
259 return S_OK;
260}
261
262void MFStream::doRead()
263{
264 bool readDone = true;
265 IUnknown *pUnk = NULL;
266 HRESULT hr = m_currentReadResult->GetObject(&pUnk);
267 if (SUCCEEDED(hr)) {
268 //do actual read
269 AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
270 ULONG cbRead;
271 Read(state->pb(), state->cb() - state->bytesRead(), &cbRead);
272 pUnk->Release();
273
274 state->setBytesRead(cbRead + state->bytesRead());
275 if (state->cb() > state->bytesRead() && !m_stream->atEnd()) {
276 readDone = false;
277 }
278 }
279
280 if (readDone) {
281 //now inform the original caller
282 m_currentReadResult->SetStatus(hr);
283 MFInvokeCallback(m_currentReadResult);
284 }
285}
286
287
288void MFStream::handleReadyRead()
289{
290 doRead();
291}
292
293void MFStream::customEvent(QEvent *event)
294{
295 if (event->type() != QEvent::User) {
296 QObject::customEvent(event);
297 return;
298 }
299 doRead();
300}
301
302//AsyncReadState is a helper class used in BeginRead for asynchronous operation
303//to record some BeginRead parameters, so these parameters could be
304//used later when actually executing the read operation in another thread.
305MFStream::AsyncReadState::AsyncReadState(BYTE *pb, ULONG cb)
306 : m_cRef(1)
307 , m_pb(pb)
308 , m_cb(cb)
309 , m_cbRead(0)
310{
311}
312
313//from IUnknown
314STDMETHODIMP MFStream::AsyncReadState::QueryInterface(REFIID riid, LPVOID *ppvObject)
315{
316 if (!ppvObject)
317 return E_POINTER;
318
319 if (riid == IID_IUnknown) {
320 *ppvObject = static_cast<IUnknown*>(this);
321 } else {
322 *ppvObject = NULL;
323 return E_NOINTERFACE;
324 }
325 AddRef();
326 return S_OK;
327}
328
329STDMETHODIMP_(ULONG) MFStream::AsyncReadState::AddRef(void)
330{
331 return InterlockedIncrement(&m_cRef);
332}
333
334STDMETHODIMP_(ULONG) MFStream::AsyncReadState::Release(void)
335{
336 LONG cRef = InterlockedDecrement(&m_cRef);
337 if (cRef == 0)
338 delete this;
339 // For thread safety, return a temporary variable.
340 return cRef;
341}
342
343BYTE* MFStream::AsyncReadState::pb() const
344{
345 return m_pb;
346}
347
348ULONG MFStream::AsyncReadState::cb() const
349{
350 return m_cb;
351}
352
353ULONG MFStream::AsyncReadState::bytesRead() const
354{
355 return m_cbRead;
356}
357
358void MFStream::AsyncReadState::setBytesRead(ULONG cbRead)
359{
360 m_cbRead = cbRead;
361}
362

Warning: That file was not part of the compilation database. It may have many parsing errors.