Audioprobe implementation for wmf backend.
authorLev Zelenskiy <lev.zelenskiy@nokia.com>
Wed, 11 Jul 2012 05:06:40 +0000 (15:06 +1000)
committerQt by Nokia <qt-info@nokia.com>
Wed, 11 Jul 2012 06:01:45 +0000 (08:01 +0200)
Change-Id: I63af91af870cb92c838c1ab5d4752815aa60a03f
Reviewed-by: Ling Hu <ling.hu@nokia.com>
src/plugins/wmf/player/mfaudioprobecontrol.cpp [new file with mode: 0644]
src/plugins/wmf/player/mfaudioprobecontrol.h [new file with mode: 0644]
src/plugins/wmf/player/mfplayerservice.cpp
src/plugins/wmf/player/mfplayersession.cpp
src/plugins/wmf/player/mfplayersession.h
src/plugins/wmf/player/player.pri
src/plugins/wmf/samplegrabber.cpp [new file with mode: 0644]
src/plugins/wmf/samplegrabber.h [new file with mode: 0644]
src/plugins/wmf/wmf.pro

diff --git a/src/plugins/wmf/player/mfaudioprobecontrol.cpp b/src/plugins/wmf/player/mfaudioprobecontrol.cpp
new file mode 100644 (file)
index 0000000..c76ab91
--- /dev/null
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** 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 "mfaudioprobecontrol.h"
+
+MFAudioProbeControl::MFAudioProbeControl(QObject *parent):
+    QMediaAudioProbeControl(parent)
+{
+}
+
+MFAudioProbeControl::~MFAudioProbeControl()
+{
+}
+
+void MFAudioProbeControl::bufferProbed(const char *data, quint32 size, const QAudioFormat& format, qint64 startTime)
+{
+    if (!format.isValid())
+        return;
+
+    QAudioBuffer audioBuffer = QAudioBuffer(QByteArray(data, size), format, startTime);
+
+    {
+        QMutexLocker locker(&m_bufferMutex);
+        m_pendingBuffer = audioBuffer;
+        QMetaObject::invokeMethod(this, "bufferProbed", Qt::QueuedConnection);
+    }
+}
+
+void MFAudioProbeControl::bufferProbed()
+{
+    QAudioBuffer audioBuffer;
+    {
+        QMutexLocker locker(&m_bufferMutex);
+        if (!m_pendingBuffer.isValid())
+            return;
+        audioBuffer = m_pendingBuffer;
+    }
+    emit audioBufferProbed(audioBuffer);
+}
diff --git a/src/plugins/wmf/player/mfaudioprobecontrol.h b/src/plugins/wmf/player/mfaudioprobecontrol.h
new file mode 100644 (file)
index 0000000..878d00d
--- /dev/null
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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 MFAUDIOPROBECONTROL_H
+#define MFAUDIOPROBECONTROL_H
+
+#include <qmediaaudioprobecontrol.h>
+#include <QtCore/qmutex.h>
+#include <qaudiobuffer.h>
+
+QT_USE_NAMESPACE
+
+class MFAudioProbeControl : public QMediaAudioProbeControl
+{
+    Q_OBJECT
+public:
+    explicit MFAudioProbeControl(QObject *parent);
+    virtual ~MFAudioProbeControl();
+
+    void bufferProbed(const char *data, quint32 size, const QAudioFormat& format, qint64 startTime);
+
+private slots:
+    void bufferProbed();
+
+private:
+    QAudioBuffer m_pendingBuffer;
+    QMutex m_bufferMutex;
+};
+
+#endif
index 3372055..aad1abe 100644 (file)
@@ -49,6 +49,7 @@
 #endif
 #include "mfvideorenderercontrol.h"
 #include "mfaudioendpointcontrol.h"
+#include "mfaudioprobecontrol.h"
 #include "mfplayerservice.h"
 #include "mfplayersession.h"
 #include "mfmetadatacontrol.h"
@@ -105,6 +106,13 @@ QMediaControl* MFPlayerService::requestControl(const char *name)
             return m_videoWindowControl;
         }
 #endif
+    } else if (qstrcmp(name,QMediaAudioProbeControl_iid) == 0) {
+        if (m_session) {
+            MFAudioProbeControl *probe = new MFAudioProbeControl(this);
+            m_session->addProbe(probe);
+            return probe;
+        }
+        return 0;
     }
 
     return 0;
@@ -125,6 +133,14 @@ void MFPlayerService::releaseControl(QMediaControl *control)
         m_videoWindowControl = 0;
 #endif
     }
+
+    MFAudioProbeControl* audioProbe = qobject_cast<MFAudioProbeControl*>(control);
+    if (audioProbe) {
+        if (m_session)
+            m_session->removeProbe(audioProbe);
+        delete audioProbe;
+        return;
+    }
 }
 
 MFAudioEndpointControl* MFPlayerService::audioEndpointControl() const
index 2d56aff..bd51bba 100644 (file)
@@ -63,6 +63,7 @@
 #include <Mferror.h>
 #include <nserror.h>
 #include "sourceresolver.h"
+#include "samplegrabber.h"
 
 //#define DEBUG_MEDIAFOUNDATION
 //#define TEST_STREAMING
@@ -416,6 +417,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
     , m_scrubbing(false)
     , m_restoreRate(1)
     , m_mediaTypes(0)
+    , m_audioSampleGrabber(0)
+    , m_audioSampleGrabberNode(0)
 {
     m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
     m_sourceResolver = new SourceResolver();
@@ -437,6 +440,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
     PropVariantInit(&m_varStart);
     m_varStart.vt = VT_I8;
     m_varStart.uhVal.QuadPart = 0;
+
+    m_audioSampleGrabber = new AudioSampleGrabberCallback;
 }
 
 void MFPlayerSession::close()
@@ -470,8 +475,19 @@ void MFPlayerSession::close()
     CloseHandle(m_hCloseEvent);
 }
 
+void MFPlayerSession::addProbe(MFAudioProbeControl *probe)
+{
+    m_audioSampleGrabber->addProbe(probe);
+}
+
+void MFPlayerSession::removeProbe(MFAudioProbeControl *probe)
+{
+    m_audioSampleGrabber->removeProbe(probe);
+}
+
 MFPlayerSession::~MFPlayerSession()
 {
+    m_audioSampleGrabber->Release();
 }
 
 
@@ -579,7 +595,12 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
             if (sourceNode) {
                 IMFTopologyNode *outputNode = addOutputNode(streamDesc, mediaType, topology, 0);
                 if (outputNode) {
-                    hr = sourceNode->ConnectOutput(0, outputNode, 0);
+                    // Only install audio sample grabber for the first audio stream.
+                    if (mediaType != Audio || m_audioSampleGrabberNode || !setupAudioSampleGrabber(topology, sourceNode, outputNode)) {
+                        hr = sourceNode->ConnectOutput(0, outputNode, 0);
+                    } else {
+                        hr = S_OK;
+                    }
                     if (FAILED(hr)) {
                         emit error(QMediaPlayer::FormatError, tr("Unable to play some stream"), false);
                     }
@@ -689,6 +710,133 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc,
     return NULL;
 }
 
+bool MFPlayerSession::addAudioSampleGrabberNode(IMFTopology *topology)
+{
+    HRESULT hr = S_OK;
+    IMFMediaType *pType = 0;
+    IMFActivate *sinkActivate = 0;
+    do {
+        hr = MFCreateMediaType(&pType);
+        if (FAILED(hr))
+            break;
+
+        hr = pType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Audio);
+        if (FAILED(hr))
+            break;
+
+        hr = pType->SetGUID(MF_MT_SUBTYPE, MFAudioFormat_PCM);
+        if (FAILED(hr))
+            break;
+
+        hr = MFCreateSampleGrabberSinkActivate(pType, m_audioSampleGrabber, &sinkActivate);
+        if (FAILED(hr))
+            break;
+
+        // Note: Data is distorted if this attribute is enabled
+        hr = sinkActivate->SetUINT32(MF_SAMPLEGRABBERSINK_IGNORE_CLOCK, FALSE);
+        if (FAILED(hr))
+            break;
+
+        hr = MFCreateTopologyNode(MF_TOPOLOGY_OUTPUT_NODE, &m_audioSampleGrabberNode);
+        if (FAILED(hr))
+            break;
+
+        hr = m_audioSampleGrabberNode->SetObject(sinkActivate);
+        if (FAILED(hr))
+            break;
+
+        hr = m_audioSampleGrabberNode->SetUINT32(MF_TOPONODE_STREAMID, 0); // Identifier of the stream sink.
+        if (FAILED(hr))
+            break;
+
+        hr = m_audioSampleGrabberNode->SetUINT32(MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, FALSE);
+        if (FAILED(hr))
+            break;
+
+        hr = topology->AddNode(m_audioSampleGrabberNode);
+        if (FAILED(hr))
+            break;
+
+        pType->Release();
+        sinkActivate->Release();
+        return true;
+    } while (false);
+
+    if (pType)
+        pType->Release();
+    if (sinkActivate)
+        sinkActivate->Release();
+    if (m_audioSampleGrabberNode) {
+        m_audioSampleGrabberNode->Release();
+        m_audioSampleGrabberNode = NULL;
+    }
+    return false;
+}
+
+bool MFPlayerSession::setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode)
+{
+    if (!addAudioSampleGrabberNode(topology))
+        return false;
+
+    HRESULT hr = S_OK;
+    IMFTopologyNode *pTeeNode = NULL;
+
+    IMFMediaTypeHandler *typeHandler = NULL;
+    IMFMediaType *mediaType = NULL;
+    do {
+        hr = MFCreateTopologyNode(MF_TOPOLOGY_TEE_NODE, &pTeeNode);
+        if (FAILED(hr))
+            break;
+        hr = sourceNode->ConnectOutput(0, pTeeNode, 0);
+        if (FAILED(hr))
+            break;
+        hr = pTeeNode->ConnectOutput(0, outputNode, 0);
+        if (FAILED(hr))
+            break;
+        hr = pTeeNode->ConnectOutput(1, m_audioSampleGrabberNode, 0);
+        if (FAILED(hr))
+            break;
+    } while (false);
+
+    if (pTeeNode)
+        pTeeNode->Release();
+    if (mediaType)
+        mediaType->Release();
+    if (typeHandler)
+        typeHandler->Release();
+    return hr == S_OK;
+}
+
+QAudioFormat MFPlayerSession::audioFormatForMFMediaType(IMFMediaType *mediaType) const
+{
+    WAVEFORMATEX *wfx = 0;
+    UINT32 size;
+    HRESULT hr = MFCreateWaveFormatExFromMFMediaType(mediaType, &wfx, &size, MFWaveFormatExConvertFlag_Normal);
+    if (FAILED(hr))
+        return QAudioFormat();
+
+    if (size < sizeof(WAVEFORMATEX)) {
+        CoTaskMemFree(wfx);
+        return QAudioFormat();
+    }
+
+    if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
+        CoTaskMemFree(wfx);
+        return QAudioFormat();
+    }
+
+    QAudioFormat format;
+    format.setSampleRate(wfx->nSamplesPerSec);
+    format.setChannelCount(wfx->nChannels);
+    format.setSampleSize(wfx->wBitsPerSample);
+    format.setCodec("audio/pcm");
+    format.setByteOrder(QAudioFormat::LittleEndian);
+    format.setSampleType(QAudioFormat::SignedInt);
+
+    CoTaskMemFree(wfx);
+    return format;
+}
+
 void MFPlayerSession::stop(bool immediate)
 {
 #ifdef DEBUG_MEDIAFOUNDATION
@@ -1270,6 +1418,15 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
         }
         break;
     case MESessionTopologySet: {
+            if (m_audioSampleGrabberNode) {
+                IMFMediaType *mediaType = 0;
+                hr = MFGetTopoNodeCurrentType(m_audioSampleGrabberNode, 0, FALSE, &mediaType);
+                if (SUCCEEDED(hr)) {
+                    m_audioSampleGrabber->setFormat(audioFormatForMFMediaType(mediaType));
+                    mediaType->Release();
+                }
+            }
+
             if (SUCCEEDED(MFGetService(m_session, MR_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl)))) {
                 m_volumeControl->SetMasterVolume(m_volume);
                 m_volumeControl->SetMute(m_muted);
@@ -1402,4 +1559,8 @@ void MFPlayerSession::clear()
         m_netsourceStatistics->Release();
         m_netsourceStatistics = NULL;
     }
+    if (m_audioSampleGrabberNode) {
+        m_audioSampleGrabberNode->Release();
+        m_audioSampleGrabberNode = NULL;
+    }
 }
index 70ce925..969fd24 100644 (file)
@@ -54,6 +54,7 @@
 #include <QtCore/qmutex.h>
 #include <QtCore/qurl.h>
 #include <QtCore/qwaitcondition.h>
+#include <QtMultimedia/qaudioformat.h>
 
 QT_BEGIN_NAMESPACE
 class QMediaContent;
@@ -70,6 +71,8 @@ class MFVideoRendererControl;
 class MFPlayerControl;
 class MFMetaDataControl;
 class MFPlayerService;
+class AudioSampleGrabberCallback;
+class MFAudioProbeControl;
 
 class MFPlayerSession : public QObject, public IMFAsyncCallback
 {
@@ -115,6 +118,9 @@ public:
 
     void close();
 
+    void addProbe(MFAudioProbeControl* probe);
+    void removeProbe(MFAudioProbeControl* probe);
+
 Q_SIGNALS:
     void error(QMediaPlayer::Error error, QString errorString, bool isFatal);
     void sessionEvent(IMFMediaEvent  *sessionEvent);
@@ -211,6 +217,12 @@ private:
     IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
         IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
     IMFTopologyNode* addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID);
+
+    bool addAudioSampleGrabberNode(IMFTopology* topology);
+    bool setupAudioSampleGrabber(IMFTopology *topology, IMFTopologyNode *sourceNode, IMFTopologyNode *outputNode);
+    QAudioFormat audioFormatForMFMediaType(IMFMediaType *mediaType) const;
+    AudioSampleGrabberCallback *m_audioSampleGrabber;
+    IMFTopologyNode *m_audioSampleGrabberNode;
 };
 
 
index 733c790..8f28b52 100644 (file)
@@ -10,7 +10,8 @@ HEADERS += \
     $$PWD/mfplayercontrol.h \
     $$PWD/mfvideorenderercontrol.h \
     $$PWD/mfaudioendpointcontrol.h \
-    $$PWD/mfmetadatacontrol.h
+    $$PWD/mfmetadatacontrol.h \
+    $$PWD/mfaudioprobecontrol.h
 
 SOURCES += \
     $$PWD/mfplayerservice.cpp \
@@ -18,7 +19,8 @@ SOURCES += \
     $$PWD/mfplayercontrol.cpp \
     $$PWD/mfvideorenderercontrol.cpp \
     $$PWD/mfaudioendpointcontrol.cpp \
-    $$PWD/mfmetadatacontrol.cpp
+    $$PWD/mfmetadatacontrol.cpp \
+    $$PWD/mfaudioprobecontrol.cpp
 
 !isEmpty(QT.widgets.name):!simulator {
     HEADERS += $$PWD/evr9videowindowcontrol.h
diff --git a/src/plugins/wmf/samplegrabber.cpp b/src/plugins/wmf/samplegrabber.cpp
new file mode 100644 (file)
index 0000000..98757b6
--- /dev/null
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** 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 "samplegrabber.h"
+#include "mfaudioprobecontrol.h"
+
+STDMETHODIMP SampleGrabberCallback::QueryInterface(REFIID riid, void** ppv)
+{
+    if (!ppv)
+        return E_POINTER;
+    if (riid == IID_IMFSampleGrabberSinkCallback) {
+        *ppv = static_cast<IMFSampleGrabberSinkCallback*>(this);
+    } else if (riid == IID_IMFClockStateSink) {
+        *ppv = static_cast<IMFClockStateSink*>(this);
+    } else if (riid == IID_IUnknown) {
+        *ppv = static_cast<IUnknown*>(this);
+    } else {
+        *ppv =  NULL;
+        return E_NOINTERFACE;
+    }
+    AddRef();
+    return S_OK;
+}
+
+STDMETHODIMP_(ULONG) SampleGrabberCallback::AddRef()
+{
+    return InterlockedIncrement(&m_cRef);
+}
+
+STDMETHODIMP_(ULONG) SampleGrabberCallback::Release()
+{
+    ULONG cRef = InterlockedDecrement(&m_cRef);
+    if (cRef == 0) {
+        delete this;
+    }
+    return cRef;
+
+}
+
+// IMFClockStateSink methods.
+
+STDMETHODIMP SampleGrabberCallback::OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset)
+{
+    Q_UNUSED(hnsSystemTime);
+    Q_UNUSED(llClockStartOffset);
+    return S_OK;
+}
+
+STDMETHODIMP SampleGrabberCallback::OnClockStop(MFTIME hnsSystemTime)
+{
+    Q_UNUSED(hnsSystemTime);
+    return S_OK;
+}
+
+STDMETHODIMP SampleGrabberCallback::OnClockPause(MFTIME hnsSystemTime)
+{
+    Q_UNUSED(hnsSystemTime);
+    return S_OK;
+}
+
+STDMETHODIMP SampleGrabberCallback::OnClockRestart(MFTIME hnsSystemTime)
+{
+    Q_UNUSED(hnsSystemTime);
+    return S_OK;
+}
+
+STDMETHODIMP SampleGrabberCallback::OnClockSetRate(MFTIME hnsSystemTime, float flRate)
+{
+    Q_UNUSED(hnsSystemTime);
+    Q_UNUSED(flRate);
+    return S_OK;
+}
+
+// IMFSampleGrabberSink methods.
+
+STDMETHODIMP SampleGrabberCallback::OnSetPresentationClock(IMFPresentationClock* pClock)
+{
+    Q_UNUSED(pClock);
+    return S_OK;
+}
+
+STDMETHODIMP SampleGrabberCallback::OnShutdown()
+{
+    return S_OK;
+}
+
+void AudioSampleGrabberCallback::addProbe(MFAudioProbeControl* probe)
+{
+    QMutexLocker locker(&m_audioProbeMutex);
+
+    if (m_audioProbes.contains(probe))
+        return;
+
+    m_audioProbes.append(probe);
+}
+
+void AudioSampleGrabberCallback::removeProbe(MFAudioProbeControl* probe)
+{
+    QMutexLocker locker(&m_audioProbeMutex);
+    m_audioProbes.removeOne(probe);
+}
+
+void AudioSampleGrabberCallback::setFormat(const QAudioFormat& format)
+{
+    m_format = format;
+}
+
+STDMETHODIMP AudioSampleGrabberCallback::OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
+    LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
+    DWORD dwSampleSize)
+{
+    Q_UNUSED(dwSampleFlags);
+    Q_UNUSED(llSampleTime);
+    Q_UNUSED(llSampleDuration);
+
+    if (guidMajorMediaType != GUID_NULL && guidMajorMediaType != MFMediaType_Audio)
+        return S_OK;
+
+    QMutexLocker locker(&m_audioProbeMutex);
+
+    if (m_audioProbes.isEmpty())
+        return S_OK;
+
+    // Check if sample has a presentation time
+    if (llSampleTime == _I64_MAX) {
+        // Set default QAudioBuffer start time
+        llSampleTime = -1;
+    }
+
+    foreach (MFAudioProbeControl* probe, m_audioProbes)
+        probe->bufferProbed((const char*)pSampleBuffer, dwSampleSize, m_format, llSampleTime);
+
+    return S_OK;
+}
diff --git a/src/plugins/wmf/samplegrabber.h b/src/plugins/wmf/samplegrabber.h
new file mode 100644 (file)
index 0000000..e639eac
--- /dev/null
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** 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 SAMPLEGRABBER_H
+#define SAMPLEGRABBER_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qlist.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <mfapi.h>
+#include <mfidl.h>
+
+class MFAudioProbeControl;
+
+class SampleGrabberCallback : public IMFSampleGrabberSinkCallback
+{
+public:
+    // IUnknown methods
+    STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
+    STDMETHODIMP_(ULONG) AddRef();
+    STDMETHODIMP_(ULONG) Release();
+
+    // IMFClockStateSink methods
+    STDMETHODIMP OnClockStart(MFTIME hnsSystemTime, LONGLONG llClockStartOffset);
+    STDMETHODIMP OnClockStop(MFTIME hnsSystemTime);
+    STDMETHODIMP OnClockPause(MFTIME hnsSystemTime);
+    STDMETHODIMP OnClockRestart(MFTIME hnsSystemTime);
+    STDMETHODIMP OnClockSetRate(MFTIME hnsSystemTime, float flRate);
+
+    // IMFSampleGrabberSinkCallback methods
+    STDMETHODIMP OnSetPresentationClock(IMFPresentationClock* pClock);
+    STDMETHODIMP OnShutdown();
+
+protected:
+    SampleGrabberCallback() : m_cRef(1) {}
+
+private:
+    long m_cRef;
+};
+
+class AudioSampleGrabberCallback: public SampleGrabberCallback {
+public:
+    void addProbe(MFAudioProbeControl* probe);
+    void removeProbe(MFAudioProbeControl* probe);
+    void setFormat(const QAudioFormat& format);
+
+    STDMETHODIMP OnProcessSample(REFGUID guidMajorMediaType, DWORD dwSampleFlags,
+        LONGLONG llSampleTime, LONGLONG llSampleDuration, const BYTE * pSampleBuffer,
+        DWORD dwSampleSize);
+
+private:
+    QList<MFAudioProbeControl*> m_audioProbes;
+    QMutex m_audioProbeMutex;
+    QAudioFormat m_format;
+};
+
+#endif // SAMPLEGRABBER_H
index d7f596d..87555dd 100644 (file)
@@ -18,12 +18,14 @@ INCLUDEPATH += .
 HEADERS += \
     wmfserviceplugin.h \
     mfstream.h \
-    sourceresolver.h
+    sourceresolver.h \
+    samplegrabber.h
 
 SOURCES += \
     wmfserviceplugin.cpp \
     mfstream.cpp \
-    sourceresolver.cpp
+    sourceresolver.cpp \
+    samplegrabber.cpp
 
 include (player/player.pri)
 include (decoder/decoder.pri)