Audioprobe implementation for wmf backend.
Change-Id: I63af91af870cb92c838c1ab5d4752815aa60a03f Reviewed-by: Ling Hu <ling.hu@nokia.com>
This commit is contained in:
committed by
Qt by Nokia
parent
4d13a15bae
commit
afe12ea4de
77
src/plugins/wmf/player/mfaudioprobecontrol.cpp
Normal file
77
src/plugins/wmf/player/mfaudioprobecontrol.cpp
Normal file
@@ -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);
|
||||||
|
}
|
||||||
68
src/plugins/wmf/player/mfaudioprobecontrol.h
Normal file
68
src/plugins/wmf/player/mfaudioprobecontrol.h
Normal file
@@ -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
|
||||||
@@ -49,6 +49,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "mfvideorenderercontrol.h"
|
#include "mfvideorenderercontrol.h"
|
||||||
#include "mfaudioendpointcontrol.h"
|
#include "mfaudioendpointcontrol.h"
|
||||||
|
#include "mfaudioprobecontrol.h"
|
||||||
#include "mfplayerservice.h"
|
#include "mfplayerservice.h"
|
||||||
#include "mfplayersession.h"
|
#include "mfplayersession.h"
|
||||||
#include "mfmetadatacontrol.h"
|
#include "mfmetadatacontrol.h"
|
||||||
@@ -105,6 +106,13 @@ QMediaControl* MFPlayerService::requestControl(const char *name)
|
|||||||
return m_videoWindowControl;
|
return m_videoWindowControl;
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
return 0;
|
||||||
@@ -125,6 +133,14 @@ void MFPlayerService::releaseControl(QMediaControl *control)
|
|||||||
m_videoWindowControl = 0;
|
m_videoWindowControl = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MFAudioProbeControl* audioProbe = qobject_cast<MFAudioProbeControl*>(control);
|
||||||
|
if (audioProbe) {
|
||||||
|
if (m_session)
|
||||||
|
m_session->removeProbe(audioProbe);
|
||||||
|
delete audioProbe;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MFAudioEndpointControl* MFPlayerService::audioEndpointControl() const
|
MFAudioEndpointControl* MFPlayerService::audioEndpointControl() const
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
#include <Mferror.h>
|
#include <Mferror.h>
|
||||||
#include <nserror.h>
|
#include <nserror.h>
|
||||||
#include "sourceresolver.h"
|
#include "sourceresolver.h"
|
||||||
|
#include "samplegrabber.h"
|
||||||
|
|
||||||
//#define DEBUG_MEDIAFOUNDATION
|
//#define DEBUG_MEDIAFOUNDATION
|
||||||
//#define TEST_STREAMING
|
//#define TEST_STREAMING
|
||||||
@@ -416,6 +417,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
|
|||||||
, m_scrubbing(false)
|
, m_scrubbing(false)
|
||||||
, m_restoreRate(1)
|
, m_restoreRate(1)
|
||||||
, m_mediaTypes(0)
|
, m_mediaTypes(0)
|
||||||
|
, m_audioSampleGrabber(0)
|
||||||
|
, m_audioSampleGrabberNode(0)
|
||||||
{
|
{
|
||||||
m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
m_hCloseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
m_sourceResolver = new SourceResolver();
|
m_sourceResolver = new SourceResolver();
|
||||||
@@ -437,6 +440,8 @@ MFPlayerSession::MFPlayerSession(MFPlayerService *playerService)
|
|||||||
PropVariantInit(&m_varStart);
|
PropVariantInit(&m_varStart);
|
||||||
m_varStart.vt = VT_I8;
|
m_varStart.vt = VT_I8;
|
||||||
m_varStart.uhVal.QuadPart = 0;
|
m_varStart.uhVal.QuadPart = 0;
|
||||||
|
|
||||||
|
m_audioSampleGrabber = new AudioSampleGrabberCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MFPlayerSession::close()
|
void MFPlayerSession::close()
|
||||||
@@ -470,8 +475,19 @@ void MFPlayerSession::close()
|
|||||||
CloseHandle(m_hCloseEvent);
|
CloseHandle(m_hCloseEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MFPlayerSession::addProbe(MFAudioProbeControl *probe)
|
||||||
|
{
|
||||||
|
m_audioSampleGrabber->addProbe(probe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MFPlayerSession::removeProbe(MFAudioProbeControl *probe)
|
||||||
|
{
|
||||||
|
m_audioSampleGrabber->removeProbe(probe);
|
||||||
|
}
|
||||||
|
|
||||||
MFPlayerSession::~MFPlayerSession()
|
MFPlayerSession::~MFPlayerSession()
|
||||||
{
|
{
|
||||||
|
m_audioSampleGrabber->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -579,7 +595,12 @@ void MFPlayerSession::setupPlaybackTopology(IMFMediaSource *source, IMFPresentat
|
|||||||
if (sourceNode) {
|
if (sourceNode) {
|
||||||
IMFTopologyNode *outputNode = addOutputNode(streamDesc, mediaType, topology, 0);
|
IMFTopologyNode *outputNode = addOutputNode(streamDesc, mediaType, topology, 0);
|
||||||
if (outputNode) {
|
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)) {
|
if (FAILED(hr)) {
|
||||||
emit error(QMediaPlayer::FormatError, tr("Unable to play some stream"), false);
|
emit error(QMediaPlayer::FormatError, tr("Unable to play some stream"), false);
|
||||||
}
|
}
|
||||||
@@ -689,6 +710,133 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(IMFStreamDescriptor *streamDesc,
|
|||||||
return NULL;
|
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)
|
void MFPlayerSession::stop(bool immediate)
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_MEDIAFOUNDATION
|
#ifdef DEBUG_MEDIAFOUNDATION
|
||||||
@@ -1270,6 +1418,15 @@ void MFPlayerSession::handleSessionEvent(IMFMediaEvent *sessionEvent)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MESessionTopologySet: {
|
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)))) {
|
if (SUCCEEDED(MFGetService(m_session, MR_POLICY_VOLUME_SERVICE, IID_PPV_ARGS(&m_volumeControl)))) {
|
||||||
m_volumeControl->SetMasterVolume(m_volume);
|
m_volumeControl->SetMasterVolume(m_volume);
|
||||||
m_volumeControl->SetMute(m_muted);
|
m_volumeControl->SetMute(m_muted);
|
||||||
@@ -1402,4 +1559,8 @@ void MFPlayerSession::clear()
|
|||||||
m_netsourceStatistics->Release();
|
m_netsourceStatistics->Release();
|
||||||
m_netsourceStatistics = NULL;
|
m_netsourceStatistics = NULL;
|
||||||
}
|
}
|
||||||
|
if (m_audioSampleGrabberNode) {
|
||||||
|
m_audioSampleGrabberNode->Release();
|
||||||
|
m_audioSampleGrabberNode = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#include <QtCore/qmutex.h>
|
#include <QtCore/qmutex.h>
|
||||||
#include <QtCore/qurl.h>
|
#include <QtCore/qurl.h>
|
||||||
#include <QtCore/qwaitcondition.h>
|
#include <QtCore/qwaitcondition.h>
|
||||||
|
#include <QtMultimedia/qaudioformat.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QMediaContent;
|
class QMediaContent;
|
||||||
@@ -70,6 +71,8 @@ class MFVideoRendererControl;
|
|||||||
class MFPlayerControl;
|
class MFPlayerControl;
|
||||||
class MFMetaDataControl;
|
class MFMetaDataControl;
|
||||||
class MFPlayerService;
|
class MFPlayerService;
|
||||||
|
class AudioSampleGrabberCallback;
|
||||||
|
class MFAudioProbeControl;
|
||||||
|
|
||||||
class MFPlayerSession : public QObject, public IMFAsyncCallback
|
class MFPlayerSession : public QObject, public IMFAsyncCallback
|
||||||
{
|
{
|
||||||
@@ -115,6 +118,9 @@ public:
|
|||||||
|
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
void addProbe(MFAudioProbeControl* probe);
|
||||||
|
void removeProbe(MFAudioProbeControl* probe);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void error(QMediaPlayer::Error error, QString errorString, bool isFatal);
|
void error(QMediaPlayer::Error error, QString errorString, bool isFatal);
|
||||||
void sessionEvent(IMFMediaEvent *sessionEvent);
|
void sessionEvent(IMFMediaEvent *sessionEvent);
|
||||||
@@ -211,6 +217,12 @@ private:
|
|||||||
IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
|
IMFTopologyNode* addSourceNode(IMFTopology* topology, IMFMediaSource* source,
|
||||||
IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
|
IMFPresentationDescriptor* presentationDesc, IMFStreamDescriptor *streamDesc);
|
||||||
IMFTopologyNode* addOutputNode(IMFStreamDescriptor *streamDesc, MediaType& mediaType, IMFTopology* topology, DWORD sinkID);
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ HEADERS += \
|
|||||||
$$PWD/mfplayercontrol.h \
|
$$PWD/mfplayercontrol.h \
|
||||||
$$PWD/mfvideorenderercontrol.h \
|
$$PWD/mfvideorenderercontrol.h \
|
||||||
$$PWD/mfaudioendpointcontrol.h \
|
$$PWD/mfaudioendpointcontrol.h \
|
||||||
$$PWD/mfmetadatacontrol.h
|
$$PWD/mfmetadatacontrol.h \
|
||||||
|
$$PWD/mfaudioprobecontrol.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/mfplayerservice.cpp \
|
$$PWD/mfplayerservice.cpp \
|
||||||
@@ -18,7 +19,8 @@ SOURCES += \
|
|||||||
$$PWD/mfplayercontrol.cpp \
|
$$PWD/mfplayercontrol.cpp \
|
||||||
$$PWD/mfvideorenderercontrol.cpp \
|
$$PWD/mfvideorenderercontrol.cpp \
|
||||||
$$PWD/mfaudioendpointcontrol.cpp \
|
$$PWD/mfaudioendpointcontrol.cpp \
|
||||||
$$PWD/mfmetadatacontrol.cpp
|
$$PWD/mfmetadatacontrol.cpp \
|
||||||
|
$$PWD/mfaudioprobecontrol.cpp
|
||||||
|
|
||||||
!isEmpty(QT.widgets.name):!simulator {
|
!isEmpty(QT.widgets.name):!simulator {
|
||||||
HEADERS += $$PWD/evr9videowindowcontrol.h
|
HEADERS += $$PWD/evr9videowindowcontrol.h
|
||||||
|
|||||||
172
src/plugins/wmf/samplegrabber.cpp
Normal file
172
src/plugins/wmf/samplegrabber.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
95
src/plugins/wmf/samplegrabber.h
Normal file
95
src/plugins/wmf/samplegrabber.h
Normal file
@@ -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
|
||||||
@@ -18,12 +18,14 @@ INCLUDEPATH += .
|
|||||||
HEADERS += \
|
HEADERS += \
|
||||||
wmfserviceplugin.h \
|
wmfserviceplugin.h \
|
||||||
mfstream.h \
|
mfstream.h \
|
||||||
sourceresolver.h
|
sourceresolver.h \
|
||||||
|
samplegrabber.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
wmfserviceplugin.cpp \
|
wmfserviceplugin.cpp \
|
||||||
mfstream.cpp \
|
mfstream.cpp \
|
||||||
sourceresolver.cpp
|
sourceresolver.cpp \
|
||||||
|
samplegrabber.cpp
|
||||||
|
|
||||||
include (player/player.pri)
|
include (player/player.pri)
|
||||||
include (decoder/decoder.pri)
|
include (decoder/decoder.pri)
|
||||||
|
|||||||
Reference in New Issue
Block a user