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