summaryrefslogtreecommitdiffstats
path: root/src/plugins/wmf
diff options
context:
space:
mode:
authorLing Hu <ling.hu@nokia.com>2012-07-05 14:47:42 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-11 06:56:18 +0200
commit48c945bac3030c1c26dd9da9bea6e0deea7e5714 (patch)
tree4f802540ee898c738ec1606fab2f7c3503bbfd59 /src/plugins/wmf
parent51d7737c19dcffc3fc3039d3565cdea30daf0346 (diff)
Added wmf implementation for QAudioDecoderControl
Change-Id: Ib6d5c93577bd55995a9ae51e757156149890f15d Reviewed-by: Jun Zhu <jun.5.zhu@nokia.com> Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
Diffstat (limited to 'src/plugins/wmf')
-rw-r--r--src/plugins/wmf/decoder/decoder.pri14
-rw-r--r--src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp478
-rw-r--r--src/plugins/wmf/decoder/mfaudiodecodercontrol.h110
-rw-r--r--src/plugins/wmf/decoder/mfdecoderservice.cpp67
-rw-r--r--src/plugins/wmf/decoder/mfdecoderservice.h58
-rw-r--r--src/plugins/wmf/decoder/mfdecodersourcereader.cpp199
-rw-r--r--src/plugins/wmf/decoder/mfdecodersourcereader.h91
-rw-r--r--src/plugins/wmf/player/mfplayersession.cpp10
-rw-r--r--src/plugins/wmf/sourceresolver.cpp9
-rw-r--r--src/plugins/wmf/sourceresolver.h4
-rw-r--r--src/plugins/wmf/wmf.json2
-rw-r--r--src/plugins/wmf/wmf.pro1
-rw-r--r--src/plugins/wmf/wmfserviceplugin.cpp7
-rw-r--r--src/plugins/wmf/wmfserviceplugin.h2
14 files changed, 1040 insertions, 12 deletions
diff --git a/src/plugins/wmf/decoder/decoder.pri b/src/plugins/wmf/decoder/decoder.pri
new file mode 100644
index 000000000..992e710fe
--- /dev/null
+++ b/src/plugins/wmf/decoder/decoder.pri
@@ -0,0 +1,14 @@
+INCLUDEPATH += $$PWD
+
+LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lMf -lMfuuid -lMfplat \
+ -lPropsys -lmfreadwrite -lwmcodecdspuuid
+
+HEADERS += \
+ $$PWD/mfdecoderservice.h \
+ $$PWD/mfdecodersourcereader.h \
+ $$PWD/mfaudiodecodercontrol.h
+
+SOURCES += \
+ $$PWD/mfdecoderservice.cpp \
+ $$PWD/mfdecodersourcereader.cpp \
+ $$PWD/mfaudiodecodercontrol.cpp \ No newline at end of file
diff --git a/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp
new file mode 100644
index 000000000..862e9d2c8
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfaudiodecodercontrol.cpp
@@ -0,0 +1,478 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Wmcodecdsp.h"
+#include "mfaudiodecodercontrol.h"
+
+MFAudioDecoderControl::MFAudioDecoderControl(QObject *parent)
+ : QAudioDecoderControl(parent)
+ , m_decoderSourceReader(new MFDecoderSourceReader)
+ , m_sourceResolver(new SourceResolver)
+ , m_resampler(0)
+ , m_state(QAudioDecoder::StoppedState)
+ , m_device(0)
+ , m_bufferReady(false)
+ , m_loadingSource(false)
+ , m_mfOutputType(0)
+ , m_convertSample(0)
+ , m_sourceReady(false)
+ , m_resamplerDirty(false)
+{
+ CoCreateInstance(CLSID_CResamplerMediaObject, NULL, CLSCTX_INPROC_SERVER, IID_IMFTransform, (LPVOID*)(&m_resampler));
+ if (!m_resampler) {
+ qCritical("MFAudioDecoderControl: Failed to create resampler(CLSID_CResamplerMediaObject)!");
+ return;
+ }
+ m_mfInputStreamID = 0;
+ m_mfOutputStreamID = 0;
+ m_resampler->AddInputStreams(1, &m_mfInputStreamID);
+
+ connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
+ connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleMediaSourceError(long)));
+ connect(m_decoderSourceReader, SIGNAL(finished()), this, SLOT(handleSourceFinished()));
+
+ QAudioFormat defaultFormat;
+ defaultFormat.setCodec("audio/pcm");
+ setAudioFormat(defaultFormat);
+}
+
+MFAudioDecoderControl::~MFAudioDecoderControl()
+{
+ if (m_mfOutputType)
+ m_mfOutputType->Release();
+ m_decoderSourceReader->shutdown();
+ m_decoderSourceReader->Release();
+ m_sourceResolver->Release();
+ if (m_resampler)
+ m_resampler->Release();
+}
+
+QAudioDecoder::State MFAudioDecoderControl::state() const
+{
+ return m_state;
+}
+
+QString MFAudioDecoderControl::sourceFilename() const
+{
+ return m_sourceFilename;
+}
+
+void MFAudioDecoderControl::onSourceCleared()
+{
+ bool positionDirty = false;
+ bool durationDirty = false;
+ if (m_position != 0) {
+ m_position = 0;
+ positionDirty = true;
+ }
+ if (m_duration != 0) {
+ m_duration = 0;
+ durationDirty = true;
+ }
+ if (positionDirty)
+ emit positionChanged(m_position);
+ if (durationDirty)
+ emit durationChanged(m_duration);
+}
+
+void MFAudioDecoderControl::setSourceFilename(const QString &fileName)
+{
+ if (!m_device && m_sourceFilename == fileName)
+ return;
+ m_sourceReady = false;
+ m_sourceResolver->cancel();
+ m_decoderSourceReader->setSource(0, m_audioFormat);
+ m_device = 0;
+ m_sourceFilename = fileName;
+ if (!m_sourceFilename.isEmpty()) {
+ m_sourceResolver->shutdown();
+ QMediaResourceList rl;
+ rl.push_back(QMediaResource(QUrl::fromLocalFile(m_sourceFilename)));
+ m_sourceResolver->load(rl, 0);
+ m_loadingSource = true;
+ } else {
+ onSourceCleared();
+ }
+ emit sourceChanged();
+}
+
+QIODevice* MFAudioDecoderControl::sourceDevice() const
+{
+ return m_device;
+}
+
+void MFAudioDecoderControl::setSourceDevice(QIODevice *device)
+{
+ if (m_device == device && m_sourceFilename.isEmpty())
+ return;
+ m_sourceReady = false;
+ m_sourceResolver->cancel();
+ m_decoderSourceReader->setSource(0, m_audioFormat);
+ m_sourceFilename.clear();
+ m_device = device;
+ if (m_device) {
+ m_sourceResolver->shutdown();
+ m_sourceResolver->load(QMediaResourceList(), m_device);
+ m_loadingSource = true;
+ } else {
+ onSourceCleared();
+ }
+ emit sourceChanged();
+}
+
+void MFAudioDecoderControl::updateResamplerOutputType()
+{
+ m_resamplerDirty = false;
+ if (m_audioFormat == m_sourceOutputFormat)
+ return;
+ HRESULT hr = m_resampler->SetOutputType(m_mfOutputStreamID, m_mfOutputType, 0);
+ if (SUCCEEDED(hr)) {
+ MFT_OUTPUT_STREAM_INFO streamInfo;
+ m_resampler->GetOutputStreamInfo(m_mfOutputStreamID, &streamInfo);
+ if ((streamInfo.dwFlags & (MFT_OUTPUT_STREAM_PROVIDES_SAMPLES | MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)) == 0) {
+ //if resampler does not allocate output sample memory, we do it here
+ if (m_convertSample) {
+ m_convertSample->Release();
+ m_convertSample = 0;
+ }
+ if (SUCCEEDED(MFCreateSample(&m_convertSample))) {
+ IMFMediaBuffer *mbuf = 0;;
+ if (SUCCEEDED(MFCreateMemoryBuffer(streamInfo.cbSize, &mbuf))) {
+ m_convertSample->AddBuffer(mbuf);
+ mbuf->Release();
+ }
+ }
+ }
+ } else {
+ qWarning() << "MFAudioDecoderControl: failed to SetOutputType of resampler" << hr;
+ }
+}
+
+void MFAudioDecoderControl::handleMediaSourceReady()
+{
+ m_loadingSource = false;
+ m_sourceReady = true;
+ IMFMediaType *mediaType = m_decoderSourceReader->setSource(m_sourceResolver->mediaSource(), m_audioFormat);
+ m_sourceOutputFormat = QAudioFormat();
+
+ if (mediaType) {
+ m_sourceOutputFormat = m_audioFormat;
+ QAudioFormat af = m_audioFormat;
+ GUID subType;
+ if (SUCCEEDED(mediaType->GetGUID(MF_MT_SUBTYPE, &subType))) {
+ if (subType == MFAudioFormat_Float) {
+ m_sourceOutputFormat.setSampleType(QAudioFormat::Float);
+ } else {
+ m_sourceOutputFormat.setSampleType(QAudioFormat::SignedInt);
+ }
+ }
+ if (m_sourceOutputFormat.sampleType() != QAudioFormat::Float) {
+ m_sourceOutputFormat.setByteOrder(QAudioFormat::LittleEndian);
+ }
+
+ UINT32 val = 0;
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_NUM_CHANNELS, &val))) {
+ m_sourceOutputFormat.setChannelCount(int(val));
+ }
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, &val))) {
+ m_sourceOutputFormat.setSampleRate(int(val));
+ }
+ if (SUCCEEDED(mediaType->GetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, &val))) {
+ m_sourceOutputFormat.setSampleSize(int(val));
+ }
+
+ if (m_audioFormat.sampleType() != QAudioFormat::Float
+ && m_audioFormat.sampleType() != QAudioFormat::SignedInt) {
+ af.setSampleType(m_sourceOutputFormat.sampleType());
+ }
+ if (af.sampleType() == QAudioFormat::SignedInt) {
+ af.setByteOrder(QAudioFormat::LittleEndian);
+ }
+ if (m_audioFormat.channelCount() <= 0) {
+ af.setChannelCount(m_sourceOutputFormat.channelCount());
+ }
+ if (m_audioFormat.sampleRate() <= 0) {
+ af.setSampleRate(m_sourceOutputFormat.sampleRate());
+ }
+ if (m_audioFormat.sampleSize() <= 0) {
+ af.setSampleSize(m_sourceOutputFormat.sampleSize());
+ }
+ setAudioFormat(af);
+ }
+
+ if (m_sourceResolver->mediaSource()) {
+ IMFPresentationDescriptor *pd = 0;
+ if (mediaType && m_resampler) {
+ HRESULT hr = S_OK;
+ hr = m_resampler->SetInputType(m_mfInputStreamID, mediaType, 0);
+ if (SUCCEEDED(hr)) {
+ updateResamplerOutputType();
+ } else {
+ qWarning() << "MFAudioDecoderControl: failed to SetInputType of resampler" << hr;
+ }
+ }
+ if (SUCCEEDED(m_sourceResolver->mediaSource()->CreatePresentationDescriptor(&pd))) {
+ UINT64 duration = 0;
+ pd->GetUINT64(MF_PD_DURATION, &duration);
+ duration /= 10000;
+ if (m_duration != qint64(duration)) {
+ m_duration = qint64(duration);
+ emit durationChanged(m_duration);
+ }
+ }
+ if (m_state == QAudioDecoder::DecodingState) {
+ activatePipeline();
+ }
+ } else if (m_state != QAudioDecoder::StoppedState) {
+ m_state = QAudioDecoder::StoppedState;
+ emit stateChanged(m_state);
+ }
+}
+
+void MFAudioDecoderControl::handleMediaSourceError(long hr)
+{
+ Q_UNUSED(hr);
+ m_loadingSource = false;
+ m_decoderSourceReader->setSource(0, m_audioFormat);
+ if (m_state != QAudioDecoder::StoppedState) {
+ m_state = QAudioDecoder::StoppedState;
+ emit stateChanged(m_state);
+ }
+}
+
+void MFAudioDecoderControl::activatePipeline()
+{
+ Q_ASSERT(!m_bufferReady);
+ m_state = QAudioDecoder::DecodingState;
+ connect(m_decoderSourceReader, SIGNAL(sampleAdded()), this, SLOT(handleSampleAdded()));
+ if (m_resamplerDirty) {
+ updateResamplerOutputType();
+ }
+ m_decoderSourceReader->reset();
+ m_decoderSourceReader->readNextSample();
+ if (m_position != 0) {
+ m_position = 0;
+ emit positionChanged(0);
+ }
+}
+
+void MFAudioDecoderControl::start()
+{
+ if (m_state != QAudioDecoder::StoppedState)
+ return;
+
+ if (m_loadingSource) {
+ //deferred starting
+ m_state = QAudioDecoder::DecodingState;
+ emit stateChanged(m_state);
+ return;
+ }
+
+ if (!m_decoderSourceReader->mediaSource())
+ return;
+ activatePipeline();
+ emit stateChanged(m_state);
+}
+
+void MFAudioDecoderControl::stop()
+{
+ if (m_state == QAudioDecoder::StoppedState)
+ return;
+ m_state = QAudioDecoder::StoppedState;
+ disconnect(m_decoderSourceReader, SIGNAL(sampleAdded()), this, SLOT(handleSampleAdded()));
+ if (m_bufferReady) {
+ m_bufferReady = false;
+ emit bufferAvailableChanged(m_bufferReady);
+ }
+ emit stateChanged(m_state);
+}
+
+void MFAudioDecoderControl::handleSampleAdded()
+{
+ QList<IMFSample*> samples = m_decoderSourceReader->takeSamples();
+ Q_ASSERT(samples.count() > 0);
+ Q_ASSERT(!m_bufferReady);
+ Q_ASSERT(m_resampler);
+ LONGLONG sampleStartTime = 0;
+ IMFSample *firstSample = samples.first();
+ firstSample->GetSampleTime(&sampleStartTime);
+ QByteArray abuf;
+ if (m_sourceOutputFormat == m_audioFormat) {
+ //no need for resampling
+ foreach (IMFSample *s, samples) {
+ IMFMediaBuffer *buffer;
+ s->ConvertToContiguousBuffer(&buffer);
+ DWORD bufLen = 0;
+ BYTE *buf = 0;
+ if (SUCCEEDED(buffer->Lock(&buf, NULL, &bufLen))) {
+ abuf.push_back(QByteArray(reinterpret_cast<char*>(buf), bufLen));
+ buffer->Unlock();
+ }
+ buffer->Release();
+ LONGLONG sampleTime = 0, sampleDuration = 0;
+ s->GetSampleTime(&sampleTime);
+ s->GetSampleDuration(&sampleDuration);
+ m_position = qint64(sampleTime + sampleDuration) / 10000;
+ s->Release();
+ }
+ } else {
+ foreach (IMFSample *s, samples) {
+ HRESULT hr = m_resampler->ProcessInput(m_mfInputStreamID, s, 0);
+ if (SUCCEEDED(hr)) {
+ MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
+ outputDataBuffer.dwStreamID = m_mfOutputStreamID;
+ while (true) {
+ outputDataBuffer.pEvents = 0;
+ outputDataBuffer.dwStatus = 0;
+ outputDataBuffer.pSample = m_convertSample;
+ DWORD status = 0;
+ if (SUCCEEDED(m_resampler->ProcessOutput(0, 1, &outputDataBuffer, &status))) {
+ IMFMediaBuffer *buffer;
+ outputDataBuffer.pSample->ConvertToContiguousBuffer(&buffer);
+ DWORD bufLen = 0;
+ BYTE *buf = 0;
+ if (SUCCEEDED(buffer->Lock(&buf, NULL, &bufLen))) {
+ abuf.push_back(QByteArray(reinterpret_cast<char*>(buf), bufLen));
+ buffer->Unlock();
+ }
+ buffer->Release();
+ } else {
+ break;
+ }
+ }
+ }
+ LONGLONG sampleTime = 0, sampleDuration = 0;
+ s->GetSampleTime(&sampleTime);
+ s->GetSampleDuration(&sampleDuration);
+ m_position = qint64(sampleTime + sampleDuration) / 10000;
+ s->Release();
+ }
+ }
+ m_cachedAudioBuffer = QAudioBuffer(abuf, m_audioFormat, qint64(sampleStartTime / 10000));
+ m_bufferReady = true;
+ emit positionChanged(m_position);
+ emit bufferAvailableChanged(m_bufferReady);
+ emit bufferReady();
+}
+
+void MFAudioDecoderControl::handleSourceFinished()
+{
+ stop();
+ emit finished();
+}
+
+QAudioFormat MFAudioDecoderControl::audioFormat() const
+{
+ return m_audioFormat;
+}
+
+void MFAudioDecoderControl::setAudioFormat(const QAudioFormat &format)
+{
+ if (m_audioFormat == format || !m_resampler)
+ return;
+ if (format.codec() != QLatin1String("audio/x-wav") && format.codec() != QLatin1String("audio/pcm")) {
+ qWarning("MFAudioDecoderControl does not accept non-pcm audio format!");
+ return;
+ }
+ m_audioFormat = format;
+
+ if (m_audioFormat.isValid()) {
+ IMFMediaType *mediaType = 0;
+ MFCreateMediaType(&mediaType);
+ mediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
+ if (format.sampleType() == QAudioFormat::Float) {
+ mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
+ } else {
+ mediaType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
+ }
+
+ mediaType->SetUINT32(MF_MT_AUDIO_NUM_CHANNELS, UINT32(m_audioFormat.channelCount()));
+ mediaType->SetUINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, UINT32(m_audioFormat.sampleRate()));
+ UINT32 alignmentBlock = UINT32(m_audioFormat.channelCount() * m_audioFormat.sampleSize() / 8);
+ mediaType->SetUINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, alignmentBlock);
+ UINT32 avgBytesPerSec = UINT32(m_audioFormat.sampleRate() * m_audioFormat.sampleSize() / 8 * m_audioFormat.channelCount());
+ mediaType->SetUINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, avgBytesPerSec);
+ mediaType->SetUINT32(MF_MT_AUDIO_BITS_PER_SAMPLE, UINT32(m_audioFormat.sampleSize()));
+ mediaType->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE);
+
+ if (m_mfOutputType)
+ m_mfOutputType->Release();
+ m_mfOutputType = mediaType;
+ } else {
+ if (m_mfOutputType)
+ m_mfOutputType->Release();
+ m_mfOutputType = NULL;
+ }
+
+ if (m_sourceReady && m_state == QAudioDecoder::StoppedState) {
+ updateResamplerOutputType();
+ } else {
+ m_resamplerDirty = true;
+ }
+
+ emit formatChanged(m_audioFormat);
+}
+
+QAudioBuffer MFAudioDecoderControl::read()
+{
+ if (!m_bufferReady)
+ return QAudioBuffer();
+ QAudioBuffer buffer = m_cachedAudioBuffer;
+ m_bufferReady = false;
+ emit bufferAvailableChanged(m_bufferReady);
+ m_decoderSourceReader->readNextSample();
+ return buffer;
+}
+
+bool MFAudioDecoderControl::bufferAvailable() const
+{
+ return m_bufferReady;
+}
+
+qint64 MFAudioDecoderControl::position() const
+{
+ return m_position;
+}
+
+qint64 MFAudioDecoderControl::duration() const
+{
+ return m_duration;
+}
diff --git a/src/plugins/wmf/decoder/mfaudiodecodercontrol.h b/src/plugins/wmf/decoder/mfaudiodecodercontrol.h
new file mode 100644
index 000000000..2a4dbbed1
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfaudiodecodercontrol.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MFAUDIODECODERCONTROL_H
+#define MFAUDIODECODERCONTROL_H
+
+#include "qaudiodecodercontrol.h"
+#include "mfdecodersourcereader.h"
+#include "sourceresolver.h"
+
+QT_USE_NAMESPACE
+
+class MFAudioDecoderControl : public QAudioDecoderControl
+{
+ Q_OBJECT
+public:
+ MFAudioDecoderControl(QObject *parent = 0);
+ ~MFAudioDecoderControl();
+
+ QAudioDecoder::State state() const;
+
+ QString sourceFilename() const;
+ void setSourceFilename(const QString &fileName);
+
+ QIODevice* sourceDevice() const;
+ void setSourceDevice(QIODevice *device);
+
+ void start();
+ void stop();
+
+ QAudioFormat audioFormat() const;
+ void setAudioFormat(const QAudioFormat &format);
+
+ QAudioBuffer read();
+ bool bufferAvailable() const;
+
+ qint64 position() const;
+ qint64 duration() const;
+
+private Q_SLOTS:
+ void handleMediaSourceReady();
+ void handleMediaSourceError(long hr);
+ void handleSampleAdded();
+ void handleSourceFinished();
+
+private:
+ void updateResamplerOutputType();
+ void activatePipeline();
+ void onSourceCleared();
+
+ MFDecoderSourceReader *m_decoderSourceReader;
+ SourceResolver *m_sourceResolver;
+ IMFTransform *m_resampler;
+ QAudioDecoder::State m_state;
+ QString m_sourceFilename;
+ QIODevice *m_device;
+ QAudioFormat m_audioFormat;
+ DWORD m_mfInputStreamID;
+ DWORD m_mfOutputStreamID;
+ bool m_bufferReady;
+ QAudioBuffer m_cachedAudioBuffer;
+ qint64 m_duration;
+ qint64 m_position;
+ bool m_loadingSource;
+ IMFMediaType *m_mfOutputType;
+ IMFSample *m_convertSample;
+ QAudioFormat m_sourceOutputFormat;
+ bool m_sourceReady;
+ bool m_resamplerDirty;
+};
+
+#endif//MFAUDIODECODERCONTROL_H
diff --git a/src/plugins/wmf/decoder/mfdecoderservice.cpp b/src/plugins/wmf/decoder/mfdecoderservice.cpp
new file mode 100644
index 000000000..66f662399
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfdecoderservice.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mfdecoderservice.h"
+#include "mfaudiodecodercontrol.h"
+
+MFAudioDecoderService::MFAudioDecoderService(QObject *parent)
+ : QMediaService(parent)
+{
+}
+
+MFAudioDecoderService::~MFAudioDecoderService()
+{
+}
+
+QMediaControl* MFAudioDecoderService::requestControl(const char *name)
+{
+ if (qstrcmp(name, QAudioDecoderControl_iid) == 0) {
+ return new MFAudioDecoderControl(this);
+ }
+ return 0;
+}
+
+void MFAudioDecoderService::releaseControl(QMediaControl *control)
+{
+ if (control && control->inherits("MFAudioDecoderControl")) {
+ delete control;
+ }
+} \ No newline at end of file
diff --git a/src/plugins/wmf/decoder/mfdecoderservice.h b/src/plugins/wmf/decoder/mfdecoderservice.h
new file mode 100644
index 000000000..907c4922c
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfdecoderservice.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MFDECODERSERVICE_H
+#define MFDECODERSERVICE_H
+
+#include "qmediaservice.h"
+
+class MFAudioDecoderService : public QMediaService
+{
+ Q_OBJECT
+public:
+ MFAudioDecoderService(QObject *parent = 0);
+ ~MFAudioDecoderService();
+
+ QMediaControl* requestControl(const char *name);
+ void releaseControl(QMediaControl *control);
+};
+
+#endif//MFDECODERSERVICE_H
diff --git a/src/plugins/wmf/decoder/mfdecodersourcereader.cpp b/src/plugins/wmf/decoder/mfdecodersourcereader.cpp
new file mode 100644
index 000000000..04b50a19a
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfdecodersourcereader.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mfdecodersourcereader.h"
+
+MFDecoderSourceReader::MFDecoderSourceReader(QObject *parent)
+ : m_cRef(1)
+ , m_sourceReader(0)
+ , m_source(0)
+{
+ Q_UNUSED(parent)
+}
+
+void MFDecoderSourceReader::shutdown()
+{
+ if (m_source) {
+ m_source->Release();
+ m_source = NULL;
+ }
+ if (m_sourceReader) {
+ m_sourceReader->Release();
+ m_sourceReader = NULL;
+ }
+}
+
+IMFMediaSource* MFDecoderSourceReader::mediaSource()
+{
+ return m_source;
+}
+
+IMFMediaType* MFDecoderSourceReader::setSource(IMFMediaSource *source, const QAudioFormat &audioFormat)
+{
+ IMFMediaType *mediaType = NULL;
+ if (m_source == source)
+ return mediaType;
+ if (m_source) {
+ m_source->Release();
+ m_source = NULL;
+ }
+ if (m_sourceReader) {
+ m_sourceReader->Release();
+ m_sourceReader = NULL;
+ }
+ if (!source)
+ return mediaType;
+ IMFAttributes *attr = NULL;
+ MFCreateAttributes(&attr, 1);
+ if (SUCCEEDED(attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, this))) {
+ if (SUCCEEDED(MFCreateSourceReaderFromMediaSource(source, attr, &m_sourceReader))) {
+ m_source = source;
+ m_source->AddRef();
+ m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_ALL_STREAMS), FALSE);
+ m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
+ IMFMediaType *pPartialType = NULL;
+ MFCreateMediaType(&pPartialType);
+ pPartialType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
+
+ if (audioFormat.sampleType() == QAudioFormat::Float) {
+ pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_Float);
+ } else {
+ pPartialType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
+ }
+
+ m_sourceReader->SetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), NULL, pPartialType);
+ pPartialType->Release();
+ m_sourceReader->GetCurrentMediaType(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), &mediaType);
+ // Ensure the stream is selected.
+ m_sourceReader->SetStreamSelection(DWORD(MF_SOURCE_READER_FIRST_AUDIO_STREAM), TRUE);
+ }
+ attr->Release();
+ }
+ return mediaType;
+}
+
+void MFDecoderSourceReader::reset()
+{
+ if (!m_sourceReader)
+ return;
+ PROPVARIANT vPos;
+ PropVariantInit(&vPos);
+ vPos.vt = VT_I8;
+ vPos.uhVal.QuadPart = 0;
+ m_sourceReader->SetCurrentPosition(GUID_NULL, vPos);
+}
+
+void MFDecoderSourceReader::readNextSample()
+{
+ if (!m_sourceReader)
+ return;
+ m_sourceReader->ReadSample(MF_SOURCE_READER_FIRST_AUDIO_STREAM, 0, NULL, NULL, NULL, NULL);
+}
+
+QList<IMFSample*> MFDecoderSourceReader::takeSamples() //internal samples will be cleared after this
+{
+ QList<IMFSample*> samples;
+ m_samplesMutex.lock();
+ samples = m_cachedSamples;
+ m_cachedSamples.clear();
+ m_samplesMutex.unlock();
+ return samples;
+}
+
+//from IUnknown
+STDMETHODIMP MFDecoderSourceReader::QueryInterface(REFIID riid, LPVOID *ppvObject)
+{
+ if (!ppvObject)
+ return E_POINTER;
+ if (riid == IID_IMFSourceReaderCallback) {
+ *ppvObject = static_cast<IMFSourceReaderCallback*>(this);
+ } else if (riid == IID_IUnknown) {
+ *ppvObject = static_cast<IUnknown*>(this);
+ } else {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+ AddRef();
+ return S_OK;
+}
+
+STDMETHODIMP_(ULONG) MFDecoderSourceReader::AddRef(void)
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) MFDecoderSourceReader::Release(void)
+{
+ LONG cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0) {
+ this->deleteLater();
+ }
+ return cRef;
+}
+
+//from IMFSourceReaderCallback
+STDMETHODIMP MFDecoderSourceReader::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
+ DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample)
+{
+ Q_UNUSED(hrStatus);
+ Q_UNUSED(dwStreamIndex);
+ Q_UNUSED(llTimestamp);
+ if (pSample) {
+ pSample->AddRef();
+ m_samplesMutex.lock();
+ m_cachedSamples.push_back(pSample);
+ m_samplesMutex.unlock();
+ emit sampleAdded();
+ } else if ((dwStreamFlags & MF_SOURCE_READERF_ENDOFSTREAM) == MF_SOURCE_READERF_ENDOFSTREAM) {
+ emit finished();
+ }
+ return S_OK;
+}
+
+STDMETHODIMP MFDecoderSourceReader::OnFlush(DWORD)
+{
+ return S_OK;
+}
+
+STDMETHODIMP MFDecoderSourceReader::OnEvent(DWORD, IMFMediaEvent*)
+{
+ return S_OK;
+} \ No newline at end of file
diff --git a/src/plugins/wmf/decoder/mfdecodersourcereader.h b/src/plugins/wmf/decoder/mfdecodersourcereader.h
new file mode 100644
index 000000000..2f50823b3
--- /dev/null
+++ b/src/plugins/wmf/decoder/mfdecodersourcereader.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the Qt Mobility Components.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MFDECODERSOURCEREADER_H
+#define MFDECODERSOURCEREADER_H
+#include <mfapi.h>
+#include <mfidl.h>
+#include <Mfreadwrite.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmutex.h>
+#include "qaudioformat.h"
+
+QT_USE_NAMESPACE
+
+class MFDecoderSourceReader : public QObject, public IMFSourceReaderCallback
+{
+ Q_OBJECT
+public:
+ MFDecoderSourceReader(QObject *parent = 0);
+ void shutdown();
+
+ IMFMediaSource* mediaSource();
+ IMFMediaType* setSource(IMFMediaSource *source, const QAudioFormat &audioFormat);
+
+ void reset();
+ void readNextSample();
+ QList<IMFSample*> takeSamples(); //internal samples will be cleared after this
+
+ //from IUnknown
+ STDMETHODIMP QueryInterface(REFIID riid, LPVOID *ppvObject);
+ STDMETHODIMP_(ULONG) AddRef(void);
+ STDMETHODIMP_(ULONG) Release(void);
+
+ //from IMFSourceReaderCallback
+ STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
+ DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample);
+ STDMETHODIMP OnFlush(DWORD dwStreamIndex);
+ STDMETHODIMP OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent);
+
+Q_SIGNALS:
+ void sampleAdded();
+ void finished();
+
+private:
+ long m_cRef;
+ QList<IMFSample*> m_cachedSamples;
+ QMutex m_samplesMutex;
+
+ IMFSourceReader *m_sourceReader;
+ IMFMediaSource *m_source;
+};
+#endif//MFDECODERSOURCEREADER_H
diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp
index ef359b5e5..2d56aff3d 100644
--- a/src/plugins/wmf/player/mfplayersession.cpp
+++ b/src/plugins/wmf/player/mfplayersession.cpp
@@ -418,7 +418,7 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
, m_mediaTypes(0)
{
m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- m_sourceResolver = new SourceResolver(this);
+ m_sourceResolver = new SourceResolver();
QObject::connect(m_sourceResolver, SIGNAL(mediaSourceReady()), this, SLOT(handleMediaSourceReady()));
QObject::connect(m_sourceResolver, SIGNAL(error(long)), this, SLOT(handleSourceError(long)));
QObject::connect(this, SIGNAL(sessionEvent(IMFMediaEvent *)), this, SLOT(handleSessionEvent(IMFMediaEvent *)));
@@ -456,9 +456,13 @@ void MFPlayerSession::close()
if (SUCCEEDED(hr)) {
if (m_session)
m_session->Shutdown();
- m_sourceResolver->shutdown();
+ if (m_sourceResolver)
+ m_sourceResolver->shutdown();
+ }
+ if (m_sourceResolver) {
+ m_sourceResolver->Release();
+ m_sourceResolver = 0;
}
- m_sourceResolver->Release();
if (m_session)
m_session->Release();
diff --git a/src/plugins/wmf/sourceresolver.cpp b/src/plugins/wmf/sourceresolver.cpp
index 287990673..a3130d7cb 100644
--- a/src/plugins/wmf/sourceresolver.cpp
+++ b/src/plugins/wmf/sourceresolver.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@@ -53,9 +53,8 @@
stop the previous load operation if there is any.
*/
-SourceResolver::SourceResolver(QObject *parent)
- : QObject(parent)
- , m_cRef(1)
+SourceResolver::SourceResolver()
+ : m_cRef(1)
, m_cancelCookie(0)
, m_sourceResolver(0)
, m_mediaSource(0)
@@ -255,6 +254,8 @@ void SourceResolver::shutdown()
{
if (m_mediaSource) {
m_mediaSource->Shutdown();
+ m_mediaSource->Release();
+ m_mediaSource = NULL;
}
if (m_stream) {
diff --git a/src/plugins/wmf/sourceresolver.h b/src/plugins/wmf/sourceresolver.h
index f0568555a..879bea0b4 100644
--- a/src/plugins/wmf/sourceresolver.h
+++ b/src/plugins/wmf/sourceresolver.h
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@@ -49,7 +49,7 @@ class SourceResolver: public QObject, public IMFAsyncCallback
{
Q_OBJECT
public:
- SourceResolver(QObject *parent);
+ SourceResolver();
~SourceResolver();
diff --git a/src/plugins/wmf/wmf.json b/src/plugins/wmf/wmf.json
index c4a27ea01..b350cef41 100644
--- a/src/plugins/wmf/wmf.json
+++ b/src/plugins/wmf/wmf.json
@@ -1,3 +1,3 @@
{
- "Keys": ["org.qt-project.qt.mediaplayer"]
+ "Keys": ["org.qt-project.qt.mediaplayer", "org.qt-project.qt.audiodecode"]
}
diff --git a/src/plugins/wmf/wmf.pro b/src/plugins/wmf/wmf.pro
index f7e1acf1d..d7f596d46 100644
--- a/src/plugins/wmf/wmf.pro
+++ b/src/plugins/wmf/wmf.pro
@@ -26,6 +26,7 @@ SOURCES += \
sourceresolver.cpp
include (player/player.pri)
+include (decoder/decoder.pri)
OTHER_FILES += \
wmf.json
diff --git a/src/plugins/wmf/wmfserviceplugin.cpp b/src/plugins/wmf/wmfserviceplugin.cpp
index a796b81ea..4c2d21a6e 100644
--- a/src/plugins/wmf/wmfserviceplugin.cpp
+++ b/src/plugins/wmf/wmfserviceplugin.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
@@ -47,6 +47,7 @@
#ifdef QMEDIA_MEDIAFOUNDATION_PLAYER
#include "mfplayerservice.h"
#endif
+#include "mfdecoderservice.h"
#include <mfapi.h>
@@ -81,6 +82,10 @@ QMediaService* WMFServicePlugin::create(QString const& key)
return new MFPlayerService;
}
#endif
+ if (key == QLatin1String(Q_MEDIASERVICE_AUDIODECODER)) {
+ addRefCount();
+ return new MFAudioDecoderService;
+ }
//qDebug() << "unsupported key:" << key;
return 0;
}
diff --git a/src/plugins/wmf/wmfserviceplugin.h b/src/plugins/wmf/wmfserviceplugin.h
index e2672db1a..6a57eb5b4 100644
--- a/src/plugins/wmf/wmfserviceplugin.h
+++ b/src/plugins/wmf/wmfserviceplugin.h
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
-** This file is part of the Qt Mobility Components.
+** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage