summaryrefslogtreecommitdiffstats
path: root/src/plugins/wmf/player/mfstream.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/wmf/player/mfstream.cpp')
-rw-r--r--src/plugins/wmf/player/mfstream.cpp361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/plugins/wmf/player/mfstream.cpp b/src/plugins/wmf/player/mfstream.cpp
new file mode 100644
index 000000000..fab854e4a
--- /dev/null
+++ b/src/plugins/wmf/player/mfstream.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mfstream.h"
+#include <QtCore/qcoreapplication.h>
+
+//MFStream is added for supporting QIODevice type of media source.
+//It is used to delegate invocations from media foundation(through IMFByteStream) to QIODevice.
+
+MFStream::MFStream(QIODevice *stream, bool ownStream)
+ : m_cRef(1)
+ , m_stream(stream)
+ , m_ownStream(ownStream)
+ , m_currentReadResult(0)
+{
+ //Move to the thread of the stream object
+ //to make sure invocations on stream
+ //are happened in the same thread of stream object
+ this->moveToThread(stream->thread());
+ connect(stream, SIGNAL(readyRead()), this, SLOT(handleReadyRead()));
+}
+
+MFStream::~MFStream()
+{
+ if (m_currentReadResult)
+ m_currentReadResult->Release();
+ if (m_ownStream)
+ m_stream->deleteLater();
+}
+
+//from IUnknown
+STDMETHODIMP MFStream::QueryInterface(REFIID riid, LPVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ if (riid == IID_IMFByteStream) {
+ *ppvObject = static_cast<IMFByteStream*>(this);
+ } else if (riid == IID_IUnknown) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) MFStream::AddRef(void)
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) MFStream::Release(void)
+{
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0) {
+ this->deleteLater();
+ }
+ return cRef;
+}
+
+
+//from IMFByteStream
+STDMETHODIMP MFStream::GetCapabilities(DWORD *pdwCapabilities)
+{
+ if (!pdwCapabilities)
+ return E_INVALIDARG;
+ *pdwCapabilities = MFBYTESTREAM_IS_READABLE;
+ if (!m_stream->isSequential())
+ *pdwCapabilities |= MFBYTESTREAM_IS_SEEKABLE;
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::GetLength(QWORD *pqwLength)
+{
+ if (!pqwLength)
+ return E_INVALIDARG;
+ QMutexLocker locker(&m_mutex);
+ *pqwLength = QWORD(m_stream->size());
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::SetLength(QWORD)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP MFStream::GetCurrentPosition(QWORD *pqwPosition)
+{
+ if (!pqwPosition)
+ return E_INVALIDARG;
+ QMutexLocker locker(&m_mutex);
+ *pqwPosition = m_stream->pos();
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::SetCurrentPosition(QWORD qwPosition)
+{
+ QMutexLocker locker(&m_mutex);
+ //SetCurrentPosition may happend during the BeginRead/EndRead pair,
+ //refusing to execute SetCurrentPosition during that time seems to be
+ //the simplest workable solution
+ if (m_currentReadResult)
+ return S_FALSE;
+
+ bool seekOK = m_stream->seek(qint64(qwPosition));
+ if (seekOK)
+ return S_OK;
+ else
+ return S_FALSE;
+}
+
+STDMETHODIMP MFStream::IsEndOfStream(BOOL *pfEndOfStream)
+{
+ if (!pfEndOfStream)
+ return E_INVALIDARG;
+ QMutexLocker locker(&m_mutex);
+ *pfEndOfStream = m_stream->atEnd() ? TRUE : FALSE;
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::Read(BYTE *pb, ULONG cb, ULONG *pcbRead)
+{
+ QMutexLocker locker(&m_mutex);
+ qint64 read = m_stream->read((char*)(pb), qint64(cb));
+ if (pcbRead)
+ *pcbRead = ULONG(read);
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::BeginRead(BYTE *pb, ULONG cb, IMFAsyncCallback *pCallback,
+ IUnknown *punkState)
+{
+ if (!pCallback || !pb)
+ return E_INVALIDARG;
+
+ Q_ASSERT(m_currentReadResult == NULL);
+
+ AsyncReadState *state = new (std::nothrow) AsyncReadState(pb, cb);
+ if (state == NULL)
+ return E_OUTOFMEMORY;
+
+ HRESULT hr = MFCreateAsyncResult(state, pCallback, punkState, &m_currentReadResult);
+ state->Release();
+ if (FAILED(hr))
+ return hr;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+ return hr;
+}
+
+STDMETHODIMP MFStream::EndRead(IMFAsyncResult* pResult, ULONG *pcbRead)
+{
+ if (!pcbRead)
+ return E_INVALIDARG;
+ IUnknown *pUnk;
+ pResult->GetObject(&pUnk);
+ AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
+ *pcbRead = state->bytesRead();
+ pUnk->Release();
+
+ m_currentReadResult->Release();
+ m_currentReadResult = NULL;
+
+ return S_OK;
+}
+
+STDMETHODIMP MFStream::Write(const BYTE *, ULONG, ULONG *)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP MFStream::BeginWrite(const BYTE *, ULONG ,
+ IMFAsyncCallback *,
+ IUnknown *)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP MFStream::EndWrite(IMFAsyncResult *,
+ ULONG *)
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP MFStream::Seek(
+ MFBYTESTREAM_SEEK_ORIGIN SeekOrigin,
+ LONGLONG llSeekOffset,
+ DWORD,
+ QWORD *pqwCurrentPosition)
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_currentReadResult)
+ return S_FALSE;
+
+ qint64 pos = qint64(llSeekOffset);
+ switch (SeekOrigin) {
+ case msoCurrent:
+ pos += m_stream->pos();
+ break;
+ }
+ bool seekOK = m_stream->seek(pos);
+ if (*pqwCurrentPosition)
+ *pqwCurrentPosition = pos;
+ if (seekOK)
+ return S_OK;
+ else
+ return S_FALSE;
+}
+
+STDMETHODIMP MFStream::Flush()
+{
+ return E_NOTIMPL;
+}
+
+STDMETHODIMP MFStream::Close()
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_ownStream)
+ m_stream->close();
+ return S_OK;
+}
+
+void MFStream::doRead()
+{
+ bool readDone = true;
+ IUnknown *pUnk = NULL;
+ HRESULT hr = m_currentReadResult->GetObject(&pUnk);
+ if (SUCCEEDED(hr)) {
+ //do actual read
+ AsyncReadState *state = static_cast<AsyncReadState*>(pUnk);
+ ULONG cbRead;
+ Read(state->pb(), state->cb() - state->bytesRead(), &cbRead);
+ pUnk->Release();
+
+ state->setBytesRead(cbRead + state->bytesRead());
+ if (state->cb() > state->bytesRead() && !m_stream->atEnd()) {
+ readDone = false;
+ }
+ }
+
+ if (readDone) {
+ //now inform the original caller
+ m_currentReadResult->SetStatus(hr);
+ MFInvokeCallback(m_currentReadResult);
+ }
+}
+
+
+void MFStream::handleReadyRead()
+{
+ doRead();
+}
+
+void MFStream::customEvent(QEvent *event)
+{
+ if (event->type() != QEvent::User) {
+ QObject::customEvent(event);
+ return;
+ }
+ doRead();
+}
+
+//AsyncReadState is a helper class used in BeginRead for asynchronous operation
+//to record some BeginRead parameters, so these parameters could be
+//used later when actually executing the read operation in another thread.
+MFStream::AsyncReadState::AsyncReadState(BYTE *pb, ULONG cb)
+ : m_cRef(1)
+ , m_pb(pb)
+ , m_cb(cb)
+ , m_cbRead(0)
+{
+}
+
+//from IUnknown
+STDMETHODIMP MFStream::AsyncReadState::QueryInterface(REFIID riid, LPVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+
+ if (riid == IID_IUnknown) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) MFStream::AsyncReadState::AddRef(void)
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) MFStream::AsyncReadState::Release(void)
+{
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ delete this;
+ // For thread safety, return a temporary variable.
+ return cRef;
+}
+
+BYTE* MFStream::AsyncReadState::pb() const
+{
+ return m_pb;
+}
+
+ULONG MFStream::AsyncReadState::cb() const
+{
+ return m_cb;
+}
+
+ULONG MFStream::AsyncReadState::bytesRead() const
+{
+ return m_cbRead;
+}
+
+void MFStream::AsyncReadState::setBytesRead(ULONG cbRead)
+{
+ m_cbRead = cbRead;
+}