summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin McPherson <justin.mcpherson@nokia.com>2010-01-28 07:35:17 (GMT)
committerJustin McPherson <justin.mcpherson@nokia.com>2010-01-28 07:35:17 (GMT)
commit7123ef04484f283ffa30ece8cb73f541bd81e830 (patch)
tree623d258acf0c13e59ddb1e18e1e331fc73579958
parent11e4882fdde6efba2b3fef6805801a290ad15fb0 (diff)
downloadQt-7123ef04484f283ffa30ece8cb73f541bd81e830.zip
Qt-7123ef04484f283ffa30ece8cb73f541bd81e830.tar.gz
Qt-7123ef04484f283ffa30ece8cb73f541bd81e830.tar.bz2
Multimedia; Add directshow backend
-rw-r--r--src/plugins/mediaservices/directshow/directshow.pro14
-rw-r--r--src/plugins/mediaservices/directshow/dsserviceplugin.cpp189
-rw-r--r--src/plugins/mediaservices/directshow/dsserviceplugin.h77
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp147
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h90
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp160
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h83
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h78
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp501
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h126
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp603
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h145
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp158
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h85
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp229
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h78
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp351
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h98
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp140
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h81
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp369
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h147
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp1235
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h208
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp394
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h126
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp87
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h75
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp93
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h82
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri43
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp91
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h77
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp600
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h182
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp308
-rw-r--r--src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h112
-rw-r--r--src/plugins/mediaservices/mediaservices.pro2
38 files changed, 7664 insertions, 0 deletions
diff --git a/src/plugins/mediaservices/directshow/directshow.pro b/src/plugins/mediaservices/directshow/directshow.pro
new file mode 100644
index 0000000..a3080d3
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/directshow.pro
@@ -0,0 +1,14 @@
+TARGET = dsengine
+include(../../qpluginbase.pri)
+
+QT += multimedia
+
+HEADERS += dsserviceplugin.h
+SOURCES += dsserviceplugin.cpp
+
+include(mediaplayer/mediaplayer.pri)
+
+QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/mediaservices
+target.path = $$[QT_INSTALL_PLUGINS]/plugins/mediaservices
+INSTALLS += target
+
diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.cpp b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp
new file mode 100644
index 0000000..fc5d11f
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/dsserviceplugin.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/QFile>
+
+#include "dsserviceplugin.h"
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+#include "dscameraservice.h"
+#endif
+
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+#include "directshowplayerservice.h"
+#endif
+
+#include <qmediaserviceprovider.h>
+
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+#ifndef _STRSAFE_H_INCLUDED_
+#include <tchar.h>
+#endif
+#include <dshow.h>
+#include <objbase.h>
+#include <initguid.h>
+#pragma comment(lib, "strmiids.lib")
+#pragma comment(lib, "ole32.lib")
+#include <windows.h>
+#endif
+
+
+QT_BEGIN_NAMESPACE
+
+QStringList DSServicePlugin::keys() const
+{
+ return QStringList()
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ << QLatin1String(Q_MEDIASERVICE_CAMERA)
+#endif
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+ << QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER)
+#endif
+ ;
+}
+
+QMediaService* DSServicePlugin::create(QString const& key)
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
+ return new DSCameraService;
+#endif
+#ifdef QMEDIA_DIRECTSHOW_PLAYER
+ if (key == QLatin1String(Q_MEDIASERVICE_MEDIAPLAYER))
+ return new DirectShowPlayerService;
+#endif
+
+ qDebug() << "unsupported key:" << key;
+ return 0;
+}
+
+void DSServicePlugin::release(QMediaService *service)
+{
+ delete service;
+}
+
+QList<QByteArray> DSServicePlugin::devices(const QByteArray &service) const
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ return m_cameraDevices;
+ }
+#endif
+
+ return QList<QByteArray>();
+}
+
+QString DSServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+{
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ for (int i=0; i<m_cameraDevices.count(); i++)
+ if (m_cameraDevices[i] == device)
+ return m_cameraDescriptions[i];
+ }
+#endif
+ return QString();
+}
+
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+void DSServicePlugin::updateDevices() const
+{
+ m_cameraDevices.clear();
+ m_cameraDescriptions.clear();
+
+ CoInitialize(NULL);
+ ICreateDevEnum* pDevEnum = NULL;
+ IEnumMoniker* pEnum = NULL;
+ // Create the System device enumerator
+ HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
+ CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
+ reinterpret_cast<void**>(&pDevEnum));
+ if(SUCCEEDED(hr)) {
+ // Create the enumerator for the video capture category
+ hr = pDevEnum->CreateClassEnumerator(
+ CLSID_VideoInputDeviceCategory, &pEnum, 0);
+ pEnum->Reset();
+ // go through and find all video capture devices
+ IMoniker* pMoniker = NULL;
+ while(pEnum->Next(1, &pMoniker, NULL) == S_OK) {
+ IPropertyBag *pPropBag;
+ hr = pMoniker->BindToStorage(0,0,IID_IPropertyBag,
+ (void**)(&pPropBag));
+ if(FAILED(hr)) {
+ pMoniker->Release();
+ continue; // skip this one
+ }
+ // Find the description
+ WCHAR str[120];
+ VARIANT varName;
+ varName.vt = VT_BSTR;
+ hr = pPropBag->Read(L"FriendlyName", &varName, 0);
+ if(SUCCEEDED(hr)) {
+ StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal);
+ QString temp(QString::fromUtf16((unsigned short*)str));
+ m_cameraDevices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData());
+ hr = pPropBag->Read(L"Description", &varName, 0);
+ StringCchCopyW(str,sizeof(str)/sizeof(str[0]),varName.bstrVal);
+ QString temp2(QString::fromUtf16((unsigned short*)str));
+ m_cameraDescriptions.append(temp2);
+ }
+ pPropBag->Release();
+ pMoniker->Release();
+ }
+ }
+ CoUninitialize();
+}
+#endif
+
+QT_END_NAMESPACE
+
+Q_EXPORT_PLUGIN2(dsengine, DSServicePlugin);
+
diff --git a/src/plugins/mediaservices/directshow/dsserviceplugin.h b/src/plugins/mediaservices/directshow/dsserviceplugin.h
new file mode 100644
index 0000000..3c6f1b8
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/dsserviceplugin.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DSSERVICEPLUGIN_H
+#define DSSERVICEPLUGIN_H
+
+#include <qmediaserviceproviderplugin.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class DSServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
+public:
+ QStringList keys() const;
+ QMediaService* create(QString const& key);
+ void release(QMediaService *service);
+
+ QList<QByteArray> devices(const QByteArray &service) const;
+ QString deviceDescription(const QByteArray &service, const QByteArray &device);
+
+private:
+#ifdef QMEDIA_DIRECTSHOW_CAMERA
+ void updateDevices() const;
+
+ mutable QList<QByteArray> m_cameraDevices;
+ mutable QStringList m_cameraDescriptions;
+#endif
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // DSSERVICEPLUGIN_H
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp
new file mode 100644
index 0000000..2826ba5
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.cpp
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowaudioendpointcontrol.h"
+
+#include "directshowglobal.h"
+#include "directshowplayerservice.h"
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowAudioEndpointControl::DirectShowAudioEndpointControl(
+ DirectShowPlayerService *service, QObject *parent)
+ : QAudioEndpointSelector(parent)
+ , m_service(service)
+ , m_bindContext(0)
+ , m_deviceEnumerator(0)
+{
+ if (CreateBindCtx(0, &m_bindContext) == S_OK) {
+ m_deviceEnumerator = com_new<ICreateDevEnum>(CLSID_SystemDeviceEnum);
+
+ updateEndpoints();
+
+ setActiveEndpoint(m_defaultEndpoint);
+ }
+}
+
+DirectShowAudioEndpointControl::~DirectShowAudioEndpointControl()
+{
+ foreach (IMoniker *moniker, m_devices)
+ moniker->Release();
+
+ if (m_bindContext)
+ m_bindContext->Release();
+
+ if (m_deviceEnumerator)
+ m_deviceEnumerator->Release();
+}
+
+QList<QString> DirectShowAudioEndpointControl::availableEndpoints() const
+{
+ return m_devices.keys();
+}
+
+QString DirectShowAudioEndpointControl::endpointDescription(const QString &name) const
+{
+ return name.section(QLatin1Char('\\'), -1);
+}
+
+QString DirectShowAudioEndpointControl::defaultEndpoint() const
+{
+ return m_defaultEndpoint;
+}
+
+QString DirectShowAudioEndpointControl::activeEndpoint() const
+{
+ return m_activeEndpoint;
+}
+
+void DirectShowAudioEndpointControl::setActiveEndpoint(const QString &name)
+{
+ if (m_activeEndpoint == name)
+ return;
+
+ if (IMoniker *moniker = m_devices.value(name, 0)) {
+ IBaseFilter *filter = 0;
+
+ if (moniker->BindToObject(
+ m_bindContext,
+ 0,
+ __uuidof(IBaseFilter),
+ reinterpret_cast<void **>(&filter)) == S_OK) {
+ m_service->setAudioOutput(filter);
+
+ filter->Release();
+ }
+ }
+}
+
+void DirectShowAudioEndpointControl::updateEndpoints()
+{
+ IMalloc *oleMalloc = 0;
+ if (m_deviceEnumerator && CoGetMalloc(1, &oleMalloc) == S_OK) {
+ IEnumMoniker *monikers = 0;
+
+ if (m_deviceEnumerator->CreateClassEnumerator(
+ CLSID_AudioRendererCategory, &monikers, 0) == S_OK) {
+ for (IMoniker *moniker = 0; monikers->Next(1, &moniker, 0) == S_OK; moniker->Release()) {
+ OLECHAR *string = 0;
+ if (moniker->GetDisplayName(m_bindContext, 0, &string) == S_OK) {
+ QString deviceId = QString::fromWCharArray(string);
+ oleMalloc->Free(string);
+
+ moniker->AddRef();
+ m_devices.insert(QString::fromWCharArray(string), moniker);
+
+ if (m_defaultEndpoint.isEmpty()
+ || deviceId.endsWith(QLatin1String("Default DirectSound Device"))) {
+ m_defaultEndpoint = deviceId;
+ }
+ }
+ }
+ monikers->Release();
+ }
+ oleMalloc->Release();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h
new file mode 100644
index 0000000..9ab188c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowaudioendpointcontrol.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWAUDIOENDPOINTCONTROL_H
+#define DIRECTSHOWAUDIOENDPOINTCONTROL_H
+
+#include <QtMultimedia/qaudioendpointselector.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerService;
+
+
+class DirectShowAudioEndpointControl : public QAudioEndpointSelector
+{
+ Q_OBJECT
+public:
+ DirectShowAudioEndpointControl(DirectShowPlayerService *service, QObject *parent = 0);
+ ~DirectShowAudioEndpointControl();
+
+ QList<QString> availableEndpoints() const;
+
+ QString endpointDescription(const QString &name) const;
+
+ QString defaultEndpoint() const;
+ QString activeEndpoint() const;
+
+ void setActiveEndpoint(const QString& name);
+
+private:
+ void updateEndpoints();
+
+ DirectShowPlayerService *m_service;
+ IBindCtx *m_bindContext;
+ ICreateDevEnum *m_deviceEnumerator;
+
+ QMap<QString, IMoniker *> m_devices;
+ QString m_defaultEndpoint;
+ QString m_activeEndpoint;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp
new file mode 100644
index 0000000..4f9a19d
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <directshoweventloop.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+class DirectShowPostedEvent
+{
+public:
+ DirectShowPostedEvent(QObject *receiver, QEvent *event)
+ : receiver(receiver)
+ , event(event)
+ , next(0)
+ {
+ }
+
+ ~DirectShowPostedEvent()
+ {
+ delete event;
+ }
+
+ QObject *receiver;
+ QEvent *event;
+ DirectShowPostedEvent *next;
+};
+
+DirectShowEventLoop::DirectShowEventLoop(QObject *parent)
+ : QWinEventNotifier(parent)
+ , m_postsHead(0)
+ , m_postsTail(0)
+ , m_eventHandle(::CreateEvent(0, 0, 0, 0))
+ , m_waitHandle(::CreateEvent(0, 0, 0, 0))
+{
+ setHandle(m_eventHandle);
+ setEnabled(true);
+}
+
+DirectShowEventLoop::~DirectShowEventLoop()
+{
+ setEnabled(false);
+
+ ::CloseHandle(m_eventHandle);
+ ::CloseHandle(m_waitHandle);
+
+ for (DirectShowPostedEvent *post = m_postsHead; post; post = m_postsHead) {
+ m_postsHead = m_postsHead->next;
+
+ delete post;
+ }
+}
+
+void DirectShowEventLoop::wait(QMutex *mutex)
+{
+ ::ResetEvent(m_waitHandle);
+
+ mutex->unlock();
+
+ HANDLE handles[] = { m_eventHandle, m_waitHandle };
+ while (::WaitForMultipleObjects(2, handles, false, INFINITE) == WAIT_OBJECT_0)
+ processEvents();
+
+ mutex->lock();
+}
+
+void DirectShowEventLoop::wake()
+{
+ ::SetEvent(m_waitHandle);
+}
+
+void DirectShowEventLoop::postEvent(QObject *receiver, QEvent *event)
+{
+ QMutexLocker locker(&m_mutex);
+
+ DirectShowPostedEvent *post = new DirectShowPostedEvent(receiver, event);
+
+ if (m_postsTail)
+ m_postsTail->next = post;
+ else
+ m_postsHead = post;
+
+ m_postsTail = post;
+
+ ::SetEvent(m_eventHandle);
+}
+
+bool DirectShowEventLoop::event(QEvent *event)
+{
+ if (event->type() == QEvent::WinEventAct) {
+ processEvents();
+
+ return true;
+ } else {
+ return QWinEventNotifier::event(event);
+ }
+}
+
+void DirectShowEventLoop::processEvents()
+{
+ QMutexLocker locker(&m_mutex);
+
+ while(m_postsHead) {
+ ::ResetEvent(m_eventHandle);
+
+ DirectShowPostedEvent *post = m_postsHead;
+ m_postsHead = m_postsHead->next;
+
+ locker.unlock();
+ QCoreApplication::sendEvent(post->receiver, post->event);
+ delete post;
+ locker.relock();
+ }
+
+ m_postsTail = 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h
new file mode 100644
index 0000000..eb68af3
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshoweventloop.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWEVENTLOOP_H
+#define DIRECTSHOWEVENTLOOP_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/private/qwineventnotifier_p.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPostedEvent;
+
+class DirectShowEventLoop : public QWinEventNotifier
+{
+ Q_OBJECT
+public:
+ DirectShowEventLoop(QObject *parent = 0);
+ ~DirectShowEventLoop();
+
+ void wait(QMutex *mutex);
+ void wake();
+
+ void postEvent(QObject *object, QEvent *event);
+
+ bool event(QEvent *event);
+
+private:
+ void processEvents();
+
+ DirectShowPostedEvent *m_postsHead;
+ DirectShowPostedEvent *m_postsTail;
+ HANDLE m_eventHandle;
+ HANDLE m_waitHandle;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPAC
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h
new file mode 100644
index 0000000..1c9fe54
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowglobal.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWGLOBAL_H
+#define DIRECTSHOWGLOBAL_H
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+template <typename T> T *com_cast(IUnknown *unknown)
+{
+ T *iface = 0;
+ return unknown && unknown->QueryInterface(
+ __uuidof(T), reinterpret_cast<void **>(&iface)) == S_OK
+ ? iface
+ : 0;
+}
+
+template <typename T> T *com_new(const IID &clsid)
+{
+ T *object = 0;
+ return CoCreateInstance(
+ clsid,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ __uuidof(T),
+ reinterpret_cast<void **>(&object)) == S_OK
+ ? object
+ : 0;
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp
new file mode 100644
index 0000000..dcb9a40
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.cpp
@@ -0,0 +1,501 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowioreader.h"
+
+#include "directshoweventloop.h"
+#include "directshowglobal.h"
+#include "directshowiosource.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qthread.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowSampleRequest
+{
+public:
+ DirectShowSampleRequest(
+ IMediaSample *sample, DWORD_PTR userData, LONGLONG position, LONG length, BYTE *buffer)
+ : next(0)
+ , sample(sample)
+ , userData(userData)
+ , position(position)
+ , length(length)
+ , buffer(buffer)
+ , result(S_FALSE)
+ {
+ }
+
+ DirectShowSampleRequest *remove() { DirectShowSampleRequest *n = next; delete this; return n; }
+
+ DirectShowSampleRequest *next;
+ IMediaSample *sample;
+ DWORD_PTR userData;
+ LONGLONG position;
+ LONG length;
+ BYTE *buffer;
+ HRESULT result;
+};
+
+DirectShowIOReader::DirectShowIOReader(
+ QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop)
+ : m_source(source)
+ , m_device(device)
+ , m_loop(loop)
+ , m_pendingHead(0)
+ , m_pendingTail(0)
+ , m_readyHead(0)
+ , m_readyTail(0)
+ , m_synchronousPosition(0)
+ , m_synchronousLength(0)
+ , m_synchronousBytesRead(0)
+ , m_synchronousBuffer(0)
+ , m_synchronousResult(S_OK)
+ , m_totalLength(0)
+ , m_availableLength(0)
+ , m_flushing(false)
+{
+ moveToThread(device->thread());
+
+ connect(device, SIGNAL(readyRead()), this, SLOT(readyRead()));
+}
+
+DirectShowIOReader::~DirectShowIOReader()
+{
+ flushRequests();
+}
+
+HRESULT DirectShowIOReader::QueryInterface(REFIID riid, void **ppvObject)
+{
+ return m_source->QueryInterface(riid, ppvObject);
+}
+
+ULONG DirectShowIOReader::AddRef()
+{
+ return m_source->AddRef();
+}
+
+ULONG DirectShowIOReader::Release()
+{
+ return m_source->Release();
+}
+
+// IAsyncReader
+HRESULT DirectShowIOReader::RequestAllocator(
+ IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual)
+{
+ if (!ppActual || !pProps) {
+ return E_POINTER;
+ } else {
+ ALLOCATOR_PROPERTIES actualProperties;
+
+ if (pProps->cbAlign == 0)
+ pProps->cbAlign = 1;
+
+ if (pPreferred && pPreferred->SetProperties(pProps, &actualProperties) == S_OK) {
+ pPreferred->AddRef();
+
+ *ppActual = pPreferred;
+
+ m_source->setAllocator(*ppActual);
+
+ return S_OK;
+ } else {
+ *ppActual = com_new<IMemAllocator>(CLSID_MemoryAllocator);
+
+ if (*ppActual) {
+ if ((*ppActual)->SetProperties(pProps, &actualProperties) != S_OK) {
+ (*ppActual)->Release();
+ } else {
+ m_source->setAllocator(*ppActual);
+
+ return S_OK;
+ }
+ }
+ }
+ ppActual = 0;
+
+ return E_FAIL;
+ }
+}
+
+HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!pSample) {
+ return E_POINTER;
+ } else if (m_flushing) {
+ return VFW_E_WRONG_STATE;
+ } else {
+ REFERENCE_TIME startTime = 0;
+ REFERENCE_TIME endTime = 0;
+ BYTE *buffer;
+
+ if (pSample->GetTime(&startTime, &endTime) != S_OK
+ || pSample->GetPointer(&buffer) != S_OK) {
+ return VFW_E_SAMPLE_TIME_NOT_SET;
+ } else {
+ LONGLONG position = startTime / 10000000;
+ LONG length = ((endTime - startTime) / 10000000) + 1;
+
+ DirectShowSampleRequest *request = new DirectShowSampleRequest(
+ pSample, dwUser, position, length, buffer);
+
+ if (m_pendingTail) {
+ m_pendingTail->next = request;
+ } else {
+ m_pendingHead = request;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+ }
+ m_pendingTail = request;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::WaitForNext(
+ DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser)
+{
+ if (!ppSample || !pdwUser)
+ return E_POINTER;
+
+ QMutexLocker locker(&m_mutex);
+
+ do {
+ if (m_readyHead) {
+ DirectShowSampleRequest *request = m_readyHead;
+
+ *ppSample = request->sample;
+ *pdwUser = request->userData;
+
+ HRESULT hr = request->result;
+
+ m_readyHead = request->next;
+
+ if (!m_readyHead)
+ m_readyTail = 0;
+
+ delete request;
+
+ return hr;
+ } else if (m_flushing) {
+ *ppSample = 0;
+ *pdwUser = 0;
+
+ return VFW_E_WRONG_STATE;
+ }
+ } while (m_wait.wait(&m_mutex, dwTimeout));
+
+ *ppSample = 0;
+ *pdwUser = 0;
+
+ return VFW_E_TIMEOUT;
+}
+
+HRESULT DirectShowIOReader::SyncReadAligned(IMediaSample *pSample)
+{
+ if (!pSample) {
+ return E_POINTER;
+ } else {
+ REFERENCE_TIME startTime = 0;
+ REFERENCE_TIME endTime = 0;
+ BYTE *buffer;
+
+ if (pSample->GetTime(&startTime, &endTime) != S_OK
+ || pSample->GetPointer(&buffer) != S_OK) {
+ return VFW_E_SAMPLE_TIME_NOT_SET;
+ } else {
+ LONGLONG position = startTime / 10000000;
+ LONG length = ((endTime - startTime) / 10000000) + 1;
+
+ QMutexLocker locker(&m_mutex);
+
+ if (thread() == QThread::currentThread()) {
+ qint64 bytesRead = 0;
+
+ HRESULT hr = blockingRead(position, length, buffer, &bytesRead);
+
+ if (SUCCEEDED(hr))
+ pSample->SetActualDataLength(bytesRead);
+
+ return hr;
+ } else {
+ m_synchronousPosition = position;
+ m_synchronousLength = length;
+ m_synchronousBuffer = buffer;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+
+ m_wait.wait(&m_mutex);
+
+ m_synchronousBuffer = 0;
+
+ if (SUCCEEDED(m_synchronousResult))
+ pSample->SetActualDataLength(m_synchronousBytesRead);
+
+ return m_synchronousResult;
+ }
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer)
+{
+ if (!pBuffer) {
+ return E_POINTER;
+ } else {
+ if (thread() == QThread::currentThread()) {
+ qint64 bytesRead;
+
+ return blockingRead(llPosition, lLength, pBuffer, &bytesRead);
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ m_synchronousPosition = llPosition;
+ m_synchronousLength = lLength;
+ m_synchronousBuffer = pBuffer;
+
+ m_loop->postEvent(this, new QEvent(QEvent::User));
+
+ m_wait.wait(&m_mutex);
+
+ m_synchronousBuffer = 0;
+
+ return m_synchronousResult;
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::Length(LONGLONG *pTotal, LONGLONG *pAvailable)
+{
+ if (!pTotal || !pAvailable) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *pTotal = m_totalLength;
+ *pAvailable = m_availableLength;
+
+ return S_OK;
+ }
+}
+
+
+HRESULT DirectShowIOReader::BeginFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_flushing)
+ return S_FALSE;
+
+ m_flushing = true;
+
+ flushRequests();
+
+ m_wait.wakeAll();
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOReader::EndFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_flushing)
+ return S_FALSE;
+
+ m_flushing = false;
+
+ return S_OK;
+}
+
+void DirectShowIOReader::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::User) {
+ readyRead();
+ } else {
+ QObject::customEvent(event);
+ }
+}
+
+void DirectShowIOReader::readyRead()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_availableLength = m_device->bytesAvailable() + m_device->pos();
+ m_totalLength = m_device->size();
+
+ if (m_synchronousBuffer) {
+ if (nonBlockingRead(
+ m_synchronousPosition,
+ m_synchronousLength,
+ m_synchronousBuffer,
+ &m_synchronousBytesRead,
+ &m_synchronousResult)) {
+ m_wait.wakeAll();
+ }
+ } else {
+ qint64 bytesRead = 0;
+
+ while (m_pendingHead && nonBlockingRead(
+ m_pendingHead->position,
+ m_pendingHead->length,
+ m_pendingHead->buffer,
+ &bytesRead,
+ &m_pendingHead->result)) {
+ m_pendingHead->sample->SetActualDataLength(bytesRead);
+
+ if (m_readyTail)
+ m_readyTail->next = m_pendingHead;
+ m_readyTail = m_pendingHead;
+
+ m_pendingHead = m_pendingHead->next;
+
+ m_readyTail->next = 0;
+
+ if (!m_pendingHead)
+ m_pendingTail = 0;
+
+ if (!m_readyHead)
+ m_readyHead = m_readyTail;
+
+ m_wait.wakeAll();
+ }
+ }
+}
+
+HRESULT DirectShowIOReader::blockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead)
+{
+ *bytesRead = 0;
+
+ if (qint64(position) > m_device->size())
+ return S_FALSE;
+
+ const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);
+
+ while (m_device->bytesAvailable() + m_device->pos() < maxSize) {
+ if (!m_device->waitForReadyRead(-1))
+ return S_FALSE;
+ }
+
+ if (m_device->pos() != position && !m_device->seek(position))
+ return S_FALSE;
+
+ const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());
+
+ *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);
+
+ if (*bytesRead != length) {
+ qMemSet(buffer + *bytesRead, 0, length - *bytesRead);
+
+ return S_FALSE;
+ } else {
+ return S_OK;
+ }
+}
+
+bool DirectShowIOReader::nonBlockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result)
+{
+ const qint64 maxSize = qMin<qint64>(m_device->size(), position + length);
+
+ if (position > m_device->size()) {
+ *bytesRead = 0;
+ *result = S_FALSE;
+
+ return true;
+ } else if (m_device->bytesAvailable() + m_device->pos() >= maxSize) {
+ if (m_device->pos() != position && !m_device->seek(position)) {
+ *bytesRead = 0;
+ *result = S_FALSE;
+
+ return true;
+ } else {
+ const qint64 maxBytes = qMin<qint64>(length, m_device->bytesAvailable());
+
+ *bytesRead = m_device->read(reinterpret_cast<char *>(buffer), maxBytes);
+
+ if (*bytesRead != length) {
+ qMemSet(buffer + *bytesRead, 0, length - *bytesRead);
+
+ *result = S_FALSE;
+ } else {
+ *result = S_OK;
+ }
+
+ return true;
+ }
+ } else {
+ return false;
+ }
+}
+
+void DirectShowIOReader::flushRequests()
+{
+ while (m_pendingHead) {
+ m_pendingHead->result = VFW_E_WRONG_STATE;
+
+ if (m_readyTail)
+ m_readyTail->next = m_pendingHead;
+
+ m_readyTail = m_pendingHead;
+
+ m_pendingHead = m_pendingHead->next;
+
+ m_readyTail->next = 0;
+
+ if (!m_pendingHead)
+ m_pendingTail = 0;
+
+ if (!m_readyHead)
+ m_readyHead = m_readyTail;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h
new file mode 100644
index 0000000..8cbc2f1
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowioreader.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWIOREADER_H
+#define DIRECTSHOWIOREADER_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class DirectShowEventLoop;
+class DirectShowIOSource;
+class DirectShowSampleRequest;
+
+class DirectShowIOReader : public QObject, public IAsyncReader
+{
+ Q_OBJECT
+public:
+ DirectShowIOReader(QIODevice *device, DirectShowIOSource *source, DirectShowEventLoop *loop);
+ ~DirectShowIOReader();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IAsyncReader
+ HRESULT STDMETHODCALLTYPE RequestAllocator(
+ IMemAllocator *pPreferred, ALLOCATOR_PROPERTIES *pProps, IMemAllocator **ppActual);
+
+ HRESULT STDMETHODCALLTYPE Request(IMediaSample *pSample, DWORD_PTR dwUser);
+
+ HRESULT STDMETHODCALLTYPE WaitForNext(
+ DWORD dwTimeout, IMediaSample **ppSample, DWORD_PTR *pdwUser);
+
+ HRESULT STDMETHODCALLTYPE SyncReadAligned(IMediaSample *pSample);
+
+ HRESULT STDMETHODCALLTYPE SyncRead(LONGLONG llPosition, LONG lLength, BYTE *pBuffer);
+
+ HRESULT STDMETHODCALLTYPE Length(LONGLONG *pTotal, LONGLONG *pAvailable);
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void readyRead();
+
+private:
+ HRESULT blockingRead(LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead);
+ bool nonBlockingRead(
+ LONGLONG position, LONG length, BYTE *buffer, qint64 *bytesRead, HRESULT *result);
+ void flushRequests();
+
+ DirectShowIOSource *m_source;
+ QIODevice *m_device;
+ DirectShowEventLoop *m_loop;
+ DirectShowSampleRequest *m_pendingHead;
+ DirectShowSampleRequest *m_pendingTail;
+ DirectShowSampleRequest *m_readyHead;
+ DirectShowSampleRequest *m_readyTail;
+ LONGLONG m_synchronousPosition;
+ LONG m_synchronousLength;
+ qint64 m_synchronousBytesRead;
+ BYTE *m_synchronousBuffer;
+ HRESULT m_synchronousResult;
+ LONGLONG m_totalLength;
+ LONGLONG m_availableLength;
+ bool m_flushing;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp
new file mode 100644
index 0000000..bf83dcf
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.cpp
@@ -0,0 +1,603 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowiosource.h"
+
+#include "directshowglobal.h"
+#include "directshowmediatype.h"
+#include "directshowpinenum.h"
+
+
+QT_BEGIN_NAMESPACE
+
+static const GUID directshow_subtypes[] =
+{
+ MEDIASUBTYPE_Avi,
+ MEDIASUBTYPE_WAVE,
+ MEDIASUBTYPE_NULL
+};
+
+DirectShowIOSource::DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop)
+ : m_ref(1)
+ , m_state(State_Stopped)
+ , m_graph(0)
+ , m_clock(0)
+ , m_allocator(0)
+ , m_peerPin(0)
+ , m_pinId(QLatin1String("Data"))
+ , m_reader(device, this, loop)
+{
+ QVector<AM_MEDIA_TYPE> mediaTypes;
+
+ AM_MEDIA_TYPE type =
+ {
+ MEDIATYPE_Stream, // majortype
+ MEDIASUBTYPE_NULL, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 1, // lSampleSize
+ GUID_NULL, // formattype
+ 0, // pUnk
+ 0, // cbFormat
+ 0, // pbFormat
+ };
+
+ static const int count = sizeof(directshow_subtypes) / sizeof(GUID);
+
+ for (int i = 0; i < count; ++i) {
+ type.subtype = directshow_subtypes[i];
+ mediaTypes.append(type);
+ }
+
+ setMediaTypes(mediaTypes);
+}
+
+DirectShowIOSource::~DirectShowIOSource()
+{
+ Q_ASSERT(m_ref == 0);
+}
+
+void DirectShowIOSource::setAllocator(IMemAllocator *allocator)
+{
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = allocator;
+
+ if (m_allocator)
+ m_allocator->AddRef();
+}
+
+// IUnknown
+HRESULT DirectShowIOSource::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IPersist
+ || riid == IID_IMediaFilter
+ || riid == IID_IBaseFilter) {
+ *ppvObject = static_cast<IBaseFilter *>(this);
+ } else if (riid == IID_IAMFilterMiscFlags) {
+ *ppvObject = static_cast<IAMFilterMiscFlags *>(this);
+ } else if (riid == IID_IPin) {
+ *ppvObject = static_cast<IPin *>(this);
+ } else if (riid == IID_IAsyncReader) {
+ *ppvObject = static_cast<IAsyncReader *>(&m_reader);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG DirectShowIOSource::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowIOSource::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+// IPersist
+HRESULT DirectShowIOSource::GetClassID(CLSID *pClassID)
+{
+ *pClassID = CLSID_NULL;
+
+ return S_OK;
+}
+
+// IMediaFilter
+HRESULT DirectShowIOSource::Run(REFERENCE_TIME tStart)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Running;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::Pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Paused;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::Stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = State_Stopped;
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+ Q_UNUSED(dwMilliSecsTimeout);
+
+ if (!pState) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *pState = m_state;
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::SetSyncSource(IReferenceClock *pClock)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_clock)
+ m_clock->Release();
+
+ m_clock = pClock;
+
+ if (m_clock)
+ m_clock->AddRef();
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::GetSyncSource(IReferenceClock **ppClock)
+{
+ if (!ppClock) {
+ return E_POINTER;
+ } else {
+ if (!m_clock) {
+ *ppClock = 0;
+
+ return S_FALSE;
+ } else {
+ m_clock->AddRef();
+
+ *ppClock = m_clock;
+
+ return S_OK;
+ }
+ }
+}
+
+// IBaseFilter
+HRESULT DirectShowIOSource::EnumPins(IEnumPins **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ *ppEnum = new DirectShowPinEnum(QList<IPin *>() << this);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::FindPin(LPCWSTR Id, IPin **ppPin)
+{
+ if (!ppPin || !Id) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+ if (QString::fromWCharArray(Id) == m_pinId) {
+ AddRef();
+
+ *ppPin = this;
+
+ return S_OK;
+ } else {
+ *ppPin = 0;
+
+ return VFW_E_NOT_FOUND;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_graph = pGraph;
+ m_filterName = QString::fromWCharArray(pName);
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::QueryFilterInfo(FILTER_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ QString name = m_filterName;
+
+ if (name.length() >= MAX_FILTER_NAME)
+ name.truncate(MAX_FILTER_NAME - 1);
+
+ int length = name.toWCharArray(pInfo->achName);
+ pInfo->achName[length] = '\0';
+
+ if (m_graph)
+ m_graph->AddRef();
+
+ pInfo->pGraph = m_graph;
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryVendorInfo(LPWSTR *pVendorInfo)
+{
+ Q_UNUSED(pVendorInfo);
+
+ return E_NOTIMPL;
+}
+
+// IAMFilterMiscFlags
+ULONG DirectShowIOSource::GetMiscFlags()
+{
+ return AM_FILTER_MISC_FLAGS_IS_SOURCE;
+}
+
+// IPin
+HRESULT DirectShowIOSource::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
+{
+ QMutexLocker locker(&m_mutex);
+ if (!pReceivePin) {
+ return E_POINTER;
+ } else if (m_state != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ } else if (m_peerPin) {
+ return VFW_E_ALREADY_CONNECTED;
+ } else {
+ HRESULT hr = VFW_E_TYPE_NOT_ACCEPTED;
+
+ m_peerPin = pReceivePin;
+ m_peerPin->AddRef();
+
+ if (!pmt) {
+ IEnumMediaTypes *mediaTypes = 0;
+ if (pReceivePin->EnumMediaTypes(&mediaTypes) == S_OK) {
+ for (AM_MEDIA_TYPE *type = 0;
+ mediaTypes->Next(1, &type, 0) == S_OK;
+ DirectShowMediaType::deleteType(type)) {
+ switch (tryConnect(pReceivePin, type)) {
+ case S_OK:
+ DirectShowMediaType::freeData(type);
+ mediaTypes->Release();
+ return S_OK;
+ case VFW_E_NO_TRANSPORT:
+ hr = VFW_E_NO_TRANSPORT;
+ break;
+ default:
+ break;
+ }
+ }
+ mediaTypes->Release();
+ }
+ AM_MEDIA_TYPE type =
+ {
+ MEDIATYPE_Stream, // majortype
+ MEDIASUBTYPE_NULL, // subtype
+ TRUE, // bFixedSizeSamples
+ FALSE, // bTemporalCompression
+ 1, // lSampleSize
+ GUID_NULL, // formattype
+ 0, // pUnk
+ 0, // cbFormat
+ 0, // pbFormat
+ };
+
+ static const int count = sizeof(directshow_subtypes) / sizeof(GUID);
+
+ for (int i = 0; i < count; ++i) {
+ type.subtype = directshow_subtypes[i];
+
+ switch (tryConnect(pReceivePin, &type)) {
+ case S_OK:
+ return S_OK;
+ case VFW_E_NO_TRANSPORT:
+ hr = VFW_E_NO_TRANSPORT;
+ break;
+ default:
+ break;
+ }
+ }
+ } else if (pmt->majortype == MEDIATYPE_Stream && (hr = tryConnect(pReceivePin, pmt))) {
+ return S_OK;
+ }
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ m_mediaType.clear();
+
+ return hr;
+ }
+}
+
+HRESULT DirectShowIOSource::tryConnect(IPin *pin, const AM_MEDIA_TYPE *type)
+{
+ m_mediaType = *type;
+
+ HRESULT hr = pin->ReceiveConnection(this, type);
+
+ if (!SUCCEEDED(hr)) {
+ if (m_allocator) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+ } else if (!m_allocator) {
+ hr = VFW_E_NO_TRANSPORT;
+
+ if (IMemInputPin *memPin = com_cast<IMemInputPin>(pin)) {
+ if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator))) {
+ ALLOCATOR_PROPERTIES properties;
+ if (memPin->GetAllocatorRequirements(&properties) == S_OK
+ || m_allocator->GetProperties(&properties) == S_OK) {
+ if (properties.cbAlign == 0)
+ properties.cbAlign = 1;
+
+ ALLOCATOR_PROPERTIES actualProperties;
+ if (SUCCEEDED(hr = m_allocator->SetProperties(&properties, &actualProperties)))
+ hr = memPin->NotifyAllocator(m_allocator, TRUE);
+ }
+ if (!SUCCEEDED(hr)) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+ }
+ memPin->Release();
+ }
+ if (!SUCCEEDED(hr))
+ pin->Disconnect();
+ }
+ return hr;
+}
+
+HRESULT DirectShowIOSource::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
+{
+ Q_UNUSED(pConnector);
+ Q_UNUSED(pmt);
+ // Output pin.
+ return E_NOTIMPL;
+}
+
+HRESULT DirectShowIOSource::Disconnect()
+{
+ if (!m_peerPin) {
+ return S_FALSE;
+ } else if (m_state != State_Stopped) {
+ return VFW_E_NOT_STOPPED;
+ } else {
+ HRESULT hr = m_peerPin->Disconnect();
+
+ if (!SUCCEEDED(hr))
+ return hr;
+
+ if (m_allocator) {
+ m_allocator->Release();
+ m_allocator = 0;
+ }
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ m_mediaType.clear();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::ConnectedTo(IPin **ppPin)
+{
+ if (!ppPin) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ *ppPin = 0;
+
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ m_peerPin->AddRef();
+
+ *ppPin = m_peerPin;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ pmt = 0;
+
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ DirectShowMediaType::copy(pmt, m_mediaType);
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowIOSource::QueryPinInfo(PIN_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ AddRef();
+
+ pInfo->pFilter = this;
+ pInfo->dir = PINDIR_OUTPUT;
+
+ const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2);
+
+ qMemCopy(pInfo->achName, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryId(LPWSTR *Id)
+{
+ if (!Id) {
+ return E_POINTER;
+ } else {
+ const int bytes = (m_pinId.length() + 1) * 2;
+
+ *Id = static_cast<LPWSTR>(::CoTaskMemAlloc(bytes));
+
+ qMemCopy(*Id, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryAccept(const AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else if (pmt->majortype == MEDIATYPE_Stream) {
+ return S_OK;
+ } else {
+ return S_FALSE;
+ }
+}
+
+HRESULT DirectShowIOSource::EnumMediaTypes(IEnumMediaTypes **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ *ppEnum = createMediaTypeEnum();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowIOSource::QueryInternalConnections(IPin **apPin, ULONG *nPin)
+{
+ Q_UNUSED(apPin);
+ Q_UNUSED(nPin);
+
+ return E_NOTIMPL;
+}
+
+HRESULT DirectShowIOSource::EndOfStream()
+{
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::BeginFlush()
+{
+ return m_reader.BeginFlush();
+}
+
+HRESULT DirectShowIOSource::EndFlush()
+{
+ return m_reader.EndFlush();
+}
+
+HRESULT DirectShowIOSource::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+ Q_UNUSED(tStart);
+ Q_UNUSED(tStop);
+ Q_UNUSED(dRate);
+
+ return S_OK;
+}
+
+HRESULT DirectShowIOSource::QueryDirection(PIN_DIRECTION *pPinDir)
+{
+ if (!pPinDir) {
+ return E_POINTER;
+ } else {
+ *pPinDir = PINDIR_OUTPUT;
+
+ return S_OK;
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h
new file mode 100644
index 0000000..a8ed56a
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowiosource.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWIOSOURCE_H
+#define DIRECTSHOWIOSOURCE_H
+
+#include "directshowioreader.h"
+#include "directshowmediatype.h"
+#include "directshowmediatypelist.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+class DirectShowIOSource
+ : public DirectShowMediaTypeList
+ , public IBaseFilter
+ , public IAMFilterMiscFlags
+ , public IPin
+{
+public:
+ DirectShowIOSource(QIODevice *device, DirectShowEventLoop *loop);
+ ~DirectShowIOSource();
+
+ void setAllocator(IMemAllocator *allocator);
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IPersist
+ HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+
+ // IMediaFilter
+ HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
+ HRESULT STDMETHODCALLTYPE Pause();
+ HRESULT STDMETHODCALLTYPE Stop();
+
+ HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState);
+
+ HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
+ HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock);
+
+ // IBaseFilter
+ HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
+ HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
+
+ HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
+
+ // IAMFilterMiscFlags
+ ULONG STDMETHODCALLTYPE GetMiscFlags();
+
+ // IPin
+ HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE Disconnect();
+ HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id);
+
+ HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum);
+
+ HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin);
+
+ HRESULT STDMETHODCALLTYPE EndOfStream();
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+ HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+
+ HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir);
+
+private:
+ HRESULT tryConnect(IPin *pin, const AM_MEDIA_TYPE *type);
+
+ volatile LONG m_ref;
+ FILTER_STATE m_state;
+ IFilterGraph *m_graph;
+ IReferenceClock *m_clock;
+ IMemAllocator *m_allocator;
+ IPin *m_peerPin;
+ DirectShowMediaType m_mediaType;
+ QString m_filterName;
+ const QString m_pinId;
+ QMutex m_mutex;
+ DirectShowIOReader m_reader;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp
new file mode 100644
index 0000000..8edf93e
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowmediatype.h"
+
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ struct TypeLookup
+ {
+ QVideoFrame::PixelFormat pixelFormat;
+ GUID mediaType;
+ };
+
+ static const TypeLookup qt_typeLookup[] =
+ {
+ { QVideoFrame::Format_RGB24, MEDIASUBTYPE_RGB24 },
+ { QVideoFrame::Format_RGB32, MEDIASUBTYPE_RGB32 },
+ { QVideoFrame::Format_YV12, MEDIASUBTYPE_YV12 }
+ };
+}
+
+void DirectShowMediaType::copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source)
+{
+ *target = source;
+
+ if (source.cbFormat > 0) {
+ target->pbFormat = reinterpret_cast<PBYTE>(CoTaskMemAlloc(source.cbFormat));
+ memcpy(target->pbFormat, source.pbFormat, source.cbFormat);
+ }
+ if (target->pUnk)
+ target->pUnk->AddRef();
+}
+
+void DirectShowMediaType::deleteType(AM_MEDIA_TYPE *type)
+{
+ freeData(type);
+
+ CoTaskMemFree(type);
+}
+
+void DirectShowMediaType::freeData(AM_MEDIA_TYPE *type)
+{
+ if (type->cbFormat > 0)
+ CoTaskMemFree(type->pbFormat);
+
+ if (type->pUnk)
+ type->pUnk->Release();
+}
+
+
+GUID DirectShowMediaType::convertPixelFormat(QVideoFrame::PixelFormat format)
+{
+ const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup);
+
+ for (int i = 0; i < count; ++i)
+ if (qt_typeLookup[i].pixelFormat == format)
+ return qt_typeLookup[i].mediaType;
+ return MEDIASUBTYPE_None;
+}
+
+QVideoSurfaceFormat DirectShowMediaType::formatFromType(const AM_MEDIA_TYPE &type)
+{
+ const int count = sizeof(qt_typeLookup) / sizeof(TypeLookup);
+
+ for (int i = 0; i < count; ++i) {
+ if (IsEqualGUID(qt_typeLookup[i].mediaType, type.subtype) && type.cbFormat > 0) {
+ if (IsEqualGUID(type.formattype, FORMAT_VideoInfo)) {
+ VIDEOINFOHEADER *header = reinterpret_cast<VIDEOINFOHEADER *>(type.pbFormat);
+
+ QVideoSurfaceFormat format(
+ QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)),
+ qt_typeLookup[i].pixelFormat);
+
+ if (header->AvgTimePerFrame > 0)
+ format.setFrameRate(10000 /header->AvgTimePerFrame);
+
+ format.setScanLineDirection(header->bmiHeader.biHeight < 0
+ ? QVideoSurfaceFormat::TopToBottom
+ : QVideoSurfaceFormat::BottomToTop);
+
+ return format;
+ } else if (IsEqualGUID(type.formattype, FORMAT_VideoInfo2)) {
+ VIDEOINFOHEADER2 *header = reinterpret_cast<VIDEOINFOHEADER2 *>(type.pbFormat);
+
+ QVideoSurfaceFormat format(
+ QSize(header->bmiHeader.biWidth, qAbs(header->bmiHeader.biHeight)),
+ qt_typeLookup[i].pixelFormat);
+
+ if (header->AvgTimePerFrame > 0)
+ format.setFrameRate(10000 / header->AvgTimePerFrame);
+
+ format.setScanLineDirection(header->bmiHeader.biHeight < 0
+ ? QVideoSurfaceFormat::TopToBottom
+ : QVideoSurfaceFormat::BottomToTop);
+
+ return format;
+ }
+ }
+ }
+ return QVideoSurfaceFormat();
+}
+
+int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format)
+{
+ switch (format.pixelFormat()) {
+ case QVideoFrame::Format_RGB24:
+ return format.frameWidth() * 4 + 3 - format.frameWidth() % 4;
+ case QVideoFrame::Format_RGB32:
+ return format.frameWidth() * 4;
+ case QVideoFrame::Format_YV12:
+ return format.frameWidth() + 3 - format.frameWidth() % 4;
+ default:
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h
new file mode 100644
index 0000000..3ba907e
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatype.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWMEDIATYPE_H
+#define DIRECTSHOWMEDIATYPE_H
+
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+#include <dshow.h>
+#include <dvdmedia.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class DirectShowMediaType : public AM_MEDIA_TYPE
+{
+public:
+ DirectShowMediaType() { memset(this, 0, sizeof(DirectShowMediaType)); }
+ DirectShowMediaType(const AM_MEDIA_TYPE &type) { copy(this, type); }
+ DirectShowMediaType(const DirectShowMediaType &other) { copy(this, other); }
+ DirectShowMediaType &operator =(const AM_MEDIA_TYPE &type) {
+ free(this); copy(this, type); return *this; }
+ DirectShowMediaType &operator =(const DirectShowMediaType &other) {
+ free(this); copy(this, other); return *this; }
+ ~DirectShowMediaType() { freeData(this); }
+
+ void clear() { freeData(this); memset(this, 0, sizeof(DirectShowMediaType)); }
+
+ static void copy(AM_MEDIA_TYPE *target, const AM_MEDIA_TYPE &source);
+ static void freeData(AM_MEDIA_TYPE *type);
+ static void deleteType(AM_MEDIA_TYPE *type);
+
+ static GUID convertPixelFormat(QVideoFrame::PixelFormat format);
+ static QVideoSurfaceFormat formatFromType(const AM_MEDIA_TYPE &type);
+
+ static int bytesPerLine(const QVideoSurfaceFormat &format);
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp
new file mode 100644
index 0000000..f67794a
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowmediatypelist.h"
+
+#include "directshowmediatype.h"
+#include "videosurfacefilter.h"
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowMediaTypeEnum : public IEnumMediaTypes
+{
+public:
+ DirectShowMediaTypeEnum(DirectShowMediaTypeList *list, int token, int index = 0);
+ ~DirectShowMediaTypeEnum();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IEnumMediaTypes
+ HRESULT STDMETHODCALLTYPE Next(
+ ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched);
+ HRESULT STDMETHODCALLTYPE Skip(ULONG cMediaTypes);
+ HRESULT STDMETHODCALLTYPE Reset();
+
+ HRESULT STDMETHODCALLTYPE Clone(IEnumMediaTypes **ppEnum);
+
+private:
+ LONG m_ref;
+ DirectShowMediaTypeList *m_list;
+ int m_mediaTypeToken;
+ int m_index;
+};
+
+
+DirectShowMediaTypeEnum::DirectShowMediaTypeEnum(
+ DirectShowMediaTypeList *list, int token, int index)
+ : m_ref(1)
+ , m_list(list)
+ , m_mediaTypeToken(token)
+ , m_index(index)
+{
+ m_list->AddRef();
+}
+
+DirectShowMediaTypeEnum::~DirectShowMediaTypeEnum()
+{
+ m_list->Release();
+}
+
+HRESULT DirectShowMediaTypeEnum::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IEnumMediaTypes) {
+ *ppvObject = static_cast<IEnumMediaTypes *>(this);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG DirectShowMediaTypeEnum::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowMediaTypeEnum::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+HRESULT DirectShowMediaTypeEnum::Next(
+ ULONG cMediaTypes, AM_MEDIA_TYPE **ppMediaTypes, ULONG *pcFetched)
+{
+ return m_list->nextMediaType(m_mediaTypeToken, &m_index, cMediaTypes, ppMediaTypes, pcFetched);
+}
+
+HRESULT DirectShowMediaTypeEnum::Skip(ULONG cMediaTypes)
+{
+ return m_list->skipMediaType(m_mediaTypeToken, &m_index, cMediaTypes);
+}
+
+HRESULT DirectShowMediaTypeEnum::Reset()
+{
+ m_mediaTypeToken = m_list->currentMediaTypeToken();
+ m_index = 0;
+
+ return S_OK;
+}
+
+HRESULT DirectShowMediaTypeEnum::Clone(IEnumMediaTypes **ppEnum)
+{
+ return m_list->cloneMediaType(m_mediaTypeToken, m_index, ppEnum);
+}
+
+
+DirectShowMediaTypeList::DirectShowMediaTypeList()
+ : m_mediaTypeToken(0)
+{
+}
+
+IEnumMediaTypes *DirectShowMediaTypeList::createMediaTypeEnum()
+{
+ return new DirectShowMediaTypeEnum(this, m_mediaTypeToken, 0);
+}
+
+
+void DirectShowMediaTypeList::setMediaTypes(const QVector<AM_MEDIA_TYPE> &types)
+{
+ ++m_mediaTypeToken;
+
+ m_mediaTypes = types;
+}
+
+
+int DirectShowMediaTypeList::currentMediaTypeToken()
+{
+ return m_mediaTypeToken;
+}
+
+HRESULT DirectShowMediaTypeList::nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount)
+{
+ if (!types || (count != 1 && !fetchedCount)) {
+ return E_POINTER;
+ } else if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ int boundedCount = qBound<int>(0, count, m_mediaTypes.count() - *index);
+
+ for (int i = 0; i < boundedCount; ++i, ++(*index)) {
+ types[i] = reinterpret_cast<AM_MEDIA_TYPE *>(CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
+
+ if (types[i]) {
+ DirectShowMediaType::copy(types[i], m_mediaTypes.at(*index));
+ } else {
+ for (--i; i >= 0; --i)
+ CoTaskMemFree(types[i]);
+
+ if (fetchedCount)
+ *fetchedCount = 0;
+
+ return E_OUTOFMEMORY;
+ }
+ }
+ if (fetchedCount)
+ *fetchedCount = boundedCount;
+
+ return boundedCount == count ? S_OK : S_FALSE;
+ }
+}
+
+HRESULT DirectShowMediaTypeList::skipMediaType(int token, int *index, ULONG count)
+{
+ if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ *index = qMin<int>(*index + count, m_mediaTypes.size());
+
+ return *index < m_mediaTypes.size() ? S_OK : S_FALSE;
+ }
+}
+
+HRESULT DirectShowMediaTypeList::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration)
+{
+ if (m_mediaTypeToken != token) {
+ return VFW_E_ENUM_OUT_OF_SYNC;
+ } else {
+ *enumeration = new DirectShowMediaTypeEnum(this, token, index);
+
+ return S_OK;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h
new file mode 100644
index 0000000..b49f24c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmediatypelist.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWMEDIATYPELIST_H
+#define DIRECTSHOWMEDIATYPELIST_H
+
+#include <QtCore/qvector.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowMediaTypeList : public IUnknown
+{
+public:
+ DirectShowMediaTypeList();
+
+ IEnumMediaTypes *createMediaTypeEnum();
+
+ void setMediaTypes(const QVector<AM_MEDIA_TYPE> &types);
+
+ virtual int currentMediaTypeToken();
+ virtual HRESULT nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount);
+ virtual HRESULT skipMediaType(int token, int *index, ULONG count);
+ virtual HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration);
+
+private:
+ int m_mediaTypeToken;
+ QVector<AM_MEDIA_TYPE> m_mediaTypes;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp
new file mode 100644
index 0000000..7335e3d
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <dshow.h>
+#include <initguid.h>
+#include <qnetwork.h>
+
+#include "directshowmetadatacontrol.h"
+
+#include "directshowplayerservice.h"
+
+#include <QtCore/qcoreapplication.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ struct QWMMetaDataKeyLookup
+ {
+ QtMedia::MetaData key;
+ const wchar_t *token;
+ };
+}
+
+static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
+{
+ { QtMedia::Title, L"Title" },
+ { QtMedia::SubTitle, L"WM/SubTitle" },
+ { QtMedia::Author, L"Author" },
+ { QtMedia::Comment, L"Comment" },
+ { QtMedia::Description, L"Description" },
+ { QtMedia::Category, L"WM/Category" },
+ { QtMedia::Genre, L"WM/Genre" },
+ //{ QtMedia::Date, 0 },
+ { QtMedia::Year, L"WM/Year" },
+ { QtMedia::UserRating, L"UserRating" },
+ //{ QtMedia::MetaDatawords, 0 },
+ { QtMedia::Language, L"Language" },
+ { QtMedia::Publisher, L"WM/Publisher" },
+ { QtMedia::Copyright, L"Copyright" },
+ { QtMedia::ParentalRating, L"ParentalRating" },
+ { QtMedia::RatingOrganisation, L"RatingOrganisation" },
+
+ // Media
+ { QtMedia::Size, L"FileSize" },
+ { QtMedia::MediaType, L"MediaType" },
+ { QtMedia::Duration, L"Duration" },
+
+ // Audio
+ { QtMedia::AudioBitRate, L"AudioBitRate" },
+ { QtMedia::AudioCodec, L"AudioCodec" },
+ { QtMedia::ChannelCount, L"ChannelCount" },
+ { QtMedia::SampleRate, L"Frequency" },
+
+ // Music
+ { QtMedia::AlbumTitle, L"WM/AlbumTitle" },
+ { QtMedia::AlbumArtist, L"WM/AlbumArtist" },
+ { QtMedia::ContributingArtist, L"Author" },
+ { QtMedia::Composer, L"WM/Composer" },
+ { QtMedia::Conductor, L"WM/Conductor" },
+ { QtMedia::Lyrics, L"WM/Lyrics" },
+ { QtMedia::Mood, L"WM/Mood" },
+ { QtMedia::TrackNumber, L"WM/TrackNumber" },
+ //{ QtMedia::TrackCount, 0 },
+ //{ QtMedia::CoverArtUriSmall, 0 },
+ //{ QtMedia::CoverArtUriLarge, 0 },
+
+ // Image/Video
+ //{ QtMedia::Resolution, 0 },
+ //{ QtMedia::PixelAspectRatio, 0 },
+
+ // Video
+ //{ QtMedia::FrameRate, 0 },
+ { QtMedia::VideoBitRate, L"VideoBitRate" },
+ { QtMedia::VideoCodec, L"VideoCodec" },
+
+ //{ QtMedia::PosterUri, 0 },
+
+ // Movie
+ { QtMedia::ChapterNumber, L"ChapterNumber" },
+ { QtMedia::Director, L"WM/Director" },
+ { QtMedia::LeadPerformer, L"LeadPerformer" },
+ { QtMedia::Writer, L"WM/Writer" },
+
+ // Photos
+ { QtMedia::CameraManufacturer, L"CameraManufacturer" },
+ { QtMedia::CameraModel, L"CameraModel" },
+ { QtMedia::Event, L"Event" },
+ { QtMedia::Subject, L"Subject" }
+};
+
+static QVariant getValue(IWMHeaderInfo *header, const wchar_t *key)
+{
+ WORD streamNumber = 0;
+ WMT_ATTR_DATATYPE type = WMT_TYPE_DWORD;
+ WORD size = 0;
+
+ if (header->GetAttributeByName(&streamNumber, key, &type, 0, &size) == S_OK) {
+ switch (type) {
+ case WMT_TYPE_DWORD:
+ if (size == sizeof(DWORD)) {
+ DWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return int(word);
+ }
+ }
+ break;
+ case WMT_TYPE_STRING:
+ {
+ QString string;
+ string.resize(size / 2 - 1);
+
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(const_cast<ushort *>(string.utf16())),
+ &size) == S_OK) {
+ return string;
+ }
+ }
+ break;
+ case WMT_TYPE_BINARY:
+ {
+ QByteArray bytes;
+ bytes.resize(size);
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(bytes.data()),
+ &size) == S_OK) {
+ return bytes;
+ }
+ }
+ break;
+ case WMT_TYPE_BOOL:
+ if (size == sizeof(DWORD)) {
+ DWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return bool(word);
+ }
+ }
+ break;
+ case WMT_TYPE_QWORD:
+ if (size == sizeof(QWORD)) {
+ QWORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return qint64(word);
+ }
+ }
+ break;
+ case WMT_TYPE_WORD:
+ if (size == sizeof(WORD)){
+ WORD word;
+ if (header->GetAttributeByName(
+ &streamNumber,
+ key,
+ &type,
+ reinterpret_cast<BYTE *>(&word),
+ &size) == S_OK) {
+ return short(word);
+ }
+ }
+ break;
+ case WMT_TYPE_GUID:
+ if (size == 16) {
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QVariant();
+}
+
+DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent)
+ : QMetaDataControl(parent)
+ , m_content(0)
+ , m_headerInfo(0)
+{
+}
+
+DirectShowMetaDataControl::~DirectShowMetaDataControl()
+{
+}
+
+bool DirectShowMetaDataControl::isWritable() const
+{
+ return false;
+}
+
+bool DirectShowMetaDataControl::isMetaDataAvailable() const
+{
+ return m_content || m_headerInfo;
+}
+
+QVariant DirectShowMetaDataControl::metaData(QtMedia::MetaData key) const
+{
+ QVariant value;
+
+ if (m_headerInfo) {
+ static const int count = sizeof(qt_wmMetaDataKeys) / sizeof(QWMMetaDataKeyLookup);
+ for (int i = 0; i < count; ++i) {
+ if (qt_wmMetaDataKeys[i].key == key) {
+ value = getValue(m_headerInfo, qt_wmMetaDataKeys[i].token);
+ break;
+ }
+ }
+ } else if (m_content) {
+ BSTR string = 0;
+
+ switch (key) {
+ case QtMedia::Author:
+ m_content->get_AuthorName(&string);
+ break;
+ case QtMedia::Title:
+ m_content->get_Title(&string);
+ break;
+ case QtMedia::ParentalRating:
+ m_content->get_Rating(&string);
+ break;
+ case QtMedia::Description:
+ m_content->get_Description(&string);
+ break;
+ case QtMedia::Copyright:
+ m_content->get_Copyright(&string);
+ break;
+ default:
+ break;
+ }
+
+ if (string) {
+ value = QString::fromUtf16(string, ::SysStringLen(string));
+
+ ::SysFreeString(string);
+ }
+ }
+ return value;
+}
+
+void DirectShowMetaDataControl::setMetaData(QtMedia::MetaData, const QVariant &)
+{
+}
+
+QList<QtMedia::MetaData> DirectShowMetaDataControl::availableMetaData() const
+{
+ return QList<QtMedia::MetaData>();
+}
+
+QVariant DirectShowMetaDataControl::extendedMetaData(const QString &) const
+{
+ return QVariant();
+}
+
+void DirectShowMetaDataControl::setExtendedMetaData(const QString &, const QVariant &)
+{
+}
+
+QStringList DirectShowMetaDataControl::availableExtendedMetaData() const
+{
+ return QStringList();
+}
+
+void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source)
+{
+ if (m_content)
+ m_content->Release();
+
+ if (m_headerInfo)
+ m_headerInfo->Release();
+
+ if (!graph || graph->QueryInterface(
+ IID_IAMMediaContent, reinterpret_cast<void **>(&m_content)) != S_OK) {
+ m_content = 0;
+ }
+
+ m_headerInfo = com_cast<IWMHeaderInfo>(source);
+
+ // DirectShowMediaPlayerService holds a lock at this point so defer emitting signals to a later
+ // time.
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(MetaDataChanged)));
+}
+
+void DirectShowMetaDataControl::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(MetaDataChanged)) {
+ event->accept();
+
+ emit metaDataChanged();
+ emit metaDataAvailableChanged(m_content || m_headerInfo);
+ } else {
+ QMetaDataControl::customEvent(event);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h
new file mode 100644
index 0000000..9bb5fcc
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowmetadatacontrol.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWMETADATACONTROL_H
+#define DIRECTSHOWMETADATACONTROL_H
+
+#include <QtMultimedia/qmetadatacontrol.h>
+
+#include <dshow.h>
+#include <qnetwork.h>
+#include <wmsdk.h>
+
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerService;
+
+
+class DirectShowMetaDataControl : public QMetaDataControl
+{
+ Q_OBJECT
+public:
+ DirectShowMetaDataControl(QObject *parent = 0);
+ ~DirectShowMetaDataControl();
+
+ bool isWritable() const;
+ bool isMetaDataAvailable() const;
+
+ QVariant metaData(QtMedia::MetaData key) const;
+ void setMetaData(QtMedia::MetaData key, const QVariant &value);
+ QList<QtMedia::MetaData> availableMetaData() const;
+
+ QVariant extendedMetaData(const QString &key) const;
+ void setExtendedMetaData(const QString &key, const QVariant &value);
+ QStringList availableExtendedMetaData() const;
+
+ void updateGraph(IFilterGraph2 *graph, IBaseFilter *source);
+
+protected:
+ void customEvent(QEvent *event);
+
+private:
+ enum Event
+ {
+ MetaDataChanged = QEvent::User
+ };
+
+ IAMMediaContent *m_content;
+ IWMHeaderInfo *m_headerInfo;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp
new file mode 100644
index 0000000..19f65da
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.cpp
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowpinenum.h"
+
+#include <QtMultimedia>
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowPinEnum::DirectShowPinEnum(const QList<IPin *> &pins)
+ : m_ref(1)
+ , m_pins(pins)
+ , m_index(0)
+{
+ foreach (IPin *pin, m_pins)
+ pin->AddRef();
+}
+
+DirectShowPinEnum::~DirectShowPinEnum()
+{
+ foreach (IPin *pin, m_pins)
+ pin->Release();
+}
+
+HRESULT DirectShowPinEnum::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (riid == IID_IUnknown
+ || riid == IID_IEnumPins) {
+ AddRef();
+
+ *ppvObject = static_cast<IEnumPins *>(this);
+
+ return S_OK;
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG DirectShowPinEnum::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG DirectShowPinEnum::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ if (ref == 0) {
+ delete this;
+ }
+
+ return ref;
+}
+
+HRESULT DirectShowPinEnum::Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched)
+{
+ if (ppPins && (pcFetched || cPins == 1)) {
+ ULONG count = qBound<ULONG>(0, cPins, m_pins.count() - m_index);
+
+ for (ULONG i = 0; i < count; ++i, ++m_index) {
+ ppPins[i] = m_pins.at(m_index);
+ ppPins[i]->AddRef();
+ }
+
+ if (pcFetched)
+ *pcFetched = count;
+
+ return count == cPins ? S_OK : S_FALSE;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT DirectShowPinEnum::Skip(ULONG cPins)
+{
+ m_index = qMin(int(m_index + cPins), m_pins.count());
+
+ return m_index < m_pins.count() ? S_OK : S_FALSE;
+}
+
+HRESULT DirectShowPinEnum::Reset()
+{
+ m_index = 0;
+
+ return S_OK;
+}
+
+HRESULT DirectShowPinEnum::Clone(IEnumPins **ppEnum)
+{
+ if (ppEnum) {
+ *ppEnum = new DirectShowPinEnum(m_pins);
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h
new file mode 100644
index 0000000..40d99ea
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowpinenum.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWPINENUM_H
+#define DIRECTSHOWPINENUM_H
+
+#include <QtCore/qlist.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPinEnum : public IEnumPins
+{
+public:
+ DirectShowPinEnum(const QList<IPin *> &pins);
+ ~DirectShowPinEnum();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IEnumPins
+ HRESULT STDMETHODCALLTYPE Next(ULONG cPins, IPin **ppPins, ULONG *pcFetched);
+ HRESULT STDMETHODCALLTYPE Skip(ULONG cPins);
+ HRESULT STDMETHODCALLTYPE Reset();
+ HRESULT STDMETHODCALLTYPE Clone(IEnumPins **ppEnum);
+
+private:
+ LONG m_ref;
+ QList<IPin *> m_pins;
+ int m_index;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp
new file mode 100644
index 0000000..a4308d7
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowplayercontrol.h"
+
+#include "directshowplayerservice.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qmath.h>
+
+
+QT_BEGIN_NAMESPACE
+
+static int volumeToDecibels(int volume)
+{
+ if (volume == 0) {
+ return -10000;
+ } else if (volume == 100) {
+ return 0;
+#ifdef QT_USE_MATH_H_FLOATS
+ } else if (sizeof(qreal) == sizeof(float)) {
+ return qRound(::log10f(float(volume) / 100) * 5000);
+#endif
+ } else {
+ return qRound(::log10(qreal(volume) / 100) * 5000);
+ }
+}
+
+static int decibelsToVolume(int dB)
+{
+ if (dB == -10000) {
+ return 0;
+ } else if (dB == 0) {
+ return 100;
+ } else {
+ return qRound(100 * qPow(10, qreal(dB) / 5000));
+ }
+}
+
+DirectShowPlayerControl::DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent)
+ : QMediaPlayerControl(parent)
+ , m_service(service)
+ , m_audio(0)
+ , m_updateProperties(0)
+ , m_state(QMediaPlayer::StoppedState)
+ , m_status(QMediaPlayer::UnknownMediaStatus)
+ , m_streamTypes(0)
+ , m_muteVolume(-1)
+ , m_duration(0)
+ , m_playbackRate(0)
+ , m_seekable(false)
+{
+}
+
+DirectShowPlayerControl::~DirectShowPlayerControl()
+{
+ if (m_audio)
+ m_audio->Release();
+}
+
+QMediaPlayer::State DirectShowPlayerControl::state() const
+{
+ return m_state;
+}
+
+QMediaPlayer::MediaStatus DirectShowPlayerControl::mediaStatus() const
+{
+ return m_status;
+}
+
+qint64 DirectShowPlayerControl::duration() const
+{
+ return m_duration;
+}
+
+qint64 DirectShowPlayerControl::position() const
+{
+ return m_service->position();
+}
+
+void DirectShowPlayerControl::setPosition(qint64 position)
+{
+ m_service->seek(position);
+}
+
+int DirectShowPlayerControl::volume() const
+{
+ if (m_muteVolume >= 0) {
+ return m_muteVolume;
+ } else if (m_audio) {
+ long dB = 0;
+
+ m_audio->get_Volume(&dB);
+
+ return decibelsToVolume(dB);
+ } else {
+ return 0;
+ }
+}
+
+void DirectShowPlayerControl::setVolume(int volume)
+{
+ int boundedVolume = qBound(0, volume, 100);
+
+ if (m_muteVolume >= 0) {
+ m_muteVolume = boundedVolume;
+
+ emit volumeChanged(m_muteVolume);
+ } else if (m_audio) {
+ m_audio->put_Volume(volumeToDecibels(volume));
+
+ emit volumeChanged(boundedVolume);
+ }
+}
+
+bool DirectShowPlayerControl::isMuted() const
+{
+ return m_muteVolume >= 0;
+}
+
+void DirectShowPlayerControl::setMuted(bool muted)
+{
+ if (muted && m_muteVolume < 0) {
+ if (m_audio) {
+ long dB = 0;
+
+ m_audio->get_Volume(&dB);
+
+ m_muteVolume = decibelsToVolume(dB);
+
+ m_audio->put_Volume(-10000);
+ } else {
+ m_muteVolume = 0;
+ }
+
+ emit mutedChanged(muted);
+ } else if (!muted && m_muteVolume >= 0) {
+ if (m_audio) {
+ m_audio->put_Volume(volumeToDecibels(m_muteVolume));
+ }
+ m_muteVolume = -1;
+
+ emit mutedChanged(muted);
+ }
+}
+
+int DirectShowPlayerControl::bufferStatus() const
+{
+ return m_service->bufferStatus();
+}
+
+bool DirectShowPlayerControl::isAudioAvailable() const
+{
+ return m_streamTypes & DirectShowPlayerService::AudioStream;
+}
+
+bool DirectShowPlayerControl::isVideoAvailable() const
+{
+ return m_streamTypes & DirectShowPlayerService::VideoStream;
+}
+
+bool DirectShowPlayerControl::isSeekable() const
+{
+ return m_seekable;
+}
+
+QMediaTimeRange DirectShowPlayerControl::availablePlaybackRanges() const
+{
+ return m_service->availablePlaybackRanges();
+}
+
+qreal DirectShowPlayerControl::playbackRate() const
+{
+ return m_playbackRate;
+}
+
+void DirectShowPlayerControl::setPlaybackRate(qreal rate)
+{
+ if (m_playbackRate != rate) {
+ m_service->setRate(rate);
+
+ emit playbackRateChanged(m_playbackRate = rate);
+ }
+}
+
+QMediaContent DirectShowPlayerControl::media() const
+{
+ return m_media;
+}
+
+const QIODevice *DirectShowPlayerControl::mediaStream() const
+{
+ return m_stream;
+}
+
+void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
+{
+ m_media = media;
+ m_stream = stream;
+
+ m_updateProperties &= PlaybackRateProperty;
+
+ m_service->load(media, stream);
+
+ emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream);
+ emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream);
+ emit durationChanged(m_duration);
+ emit seekableChanged(m_seekable);
+ emit mediaStatusChanged(m_status);
+ emit stateChanged(m_state);
+}
+
+void DirectShowPlayerControl::play()
+{
+ m_service->play();
+ emit stateChanged(m_state = QMediaPlayer::PlayingState);
+}
+
+void DirectShowPlayerControl::pause()
+{
+ m_service->pause();
+ emit stateChanged(m_state = QMediaPlayer::PausedState);
+}
+
+void DirectShowPlayerControl::stop()
+{
+ m_service->stop();
+ emit stateChanged(m_state = QMediaPlayer::StoppedState);
+}
+
+void DirectShowPlayerControl::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(PropertiesChanged)) {
+ int properties = m_updateProperties;
+ m_updateProperties = 0;
+
+ if (properties & PlaybackRateProperty)
+ emit playbackRateChanged(m_playbackRate);
+
+ if (properties & StreamTypesProperty) {
+ emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream);
+ emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream);
+ }
+
+ if (properties & DurationProperty)
+ emit durationChanged(m_duration);
+
+ if (properties & SeekableProperty)
+ emit seekableChanged(m_seekable);
+
+ if (properties & StatusProperty)
+ emit mediaStatusChanged(m_status);
+
+ if (properties & StateProperty)
+ emit stateChanged(m_state);
+
+ event->accept();
+ } else {
+ QMediaPlayerControl::customEvent(event);
+ }
+}
+
+void DirectShowPlayerControl::scheduleUpdate(int properties)
+{
+ if (m_updateProperties == 0)
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(PropertiesChanged)));
+
+ m_updateProperties |= properties;
+}
+
+void DirectShowPlayerControl::updateState(QMediaPlayer::State state)
+{
+ if (m_state != state) {
+ m_state = state;
+
+ scheduleUpdate(StateProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateStatus(QMediaPlayer::MediaStatus status)
+{
+ if (m_status != status) {
+ m_status = status;
+
+ scheduleUpdate(StatusProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateMediaInfo(qint64 duration, int streamTypes, bool seekable)
+{
+ int properties = 0;
+
+ if (m_duration != duration) {
+ m_duration = duration;
+
+ properties |= DurationProperty;
+ }
+ if (m_streamTypes != streamTypes) {
+ m_streamTypes = streamTypes;
+
+ properties |= StreamTypesProperty;
+ }
+
+ if (m_seekable != seekable) {
+ m_seekable = seekable;
+
+ properties |= SeekableProperty;
+ }
+
+ if (properties != 0)
+ scheduleUpdate(properties);
+}
+
+void DirectShowPlayerControl::updatePlaybackRate(qreal rate)
+{
+ if (m_playbackRate != rate) {
+ m_playbackRate = rate;
+
+ scheduleUpdate(PlaybackRateProperty);
+ }
+}
+
+void DirectShowPlayerControl::updateAudioOutput(IBaseFilter *filter)
+{
+ if (m_audio)
+ m_audio->Release();
+
+ m_audio = com_cast<IBasicAudio>(filter);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h
new file mode 100644
index 0000000..af2cd3f
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayercontrol.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWPLAYERCONTROL_H
+#define DIRECTSHOWPLAYERCONTROL_H
+
+#include <QtMultimedia/qmediacontent.h>
+#include <QtMultimedia/qmediaplayercontrol.h>
+
+#include <QtCore/qcoreevent.h>
+
+#include "directshowplayerservice.h"
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+public:
+ DirectShowPlayerControl(DirectShowPlayerService *service, QObject *parent = 0);
+ ~DirectShowPlayerControl();
+
+ QMediaPlayer::State state() const;
+
+ QMediaPlayer::MediaStatus mediaStatus() const;
+
+ qint64 duration() const;
+
+ qint64 position() const;
+ void setPosition(qint64 position);
+
+ int volume() const;
+ void setVolume(int volume);
+
+ bool isMuted() const;
+ void setMuted(bool muted);
+
+ int bufferStatus() const;
+
+ bool isAudioAvailable() const;
+ bool isVideoAvailable() const;
+
+ bool isSeekable() const;
+
+ QMediaTimeRange availablePlaybackRanges() const;
+
+ qreal playbackRate() const;
+ void setPlaybackRate(qreal rate);
+
+ QMediaContent media() const;
+ const QIODevice *mediaStream() const;
+ void setMedia(const QMediaContent &media, QIODevice *stream);
+
+ void play();
+ void pause();
+ void stop();
+
+ void updateState(QMediaPlayer::State state);
+ void updateStatus(QMediaPlayer::MediaStatus status);
+ void updateMediaInfo(qint64 duration, int streamTypes, bool seekable);
+ void updatePlaybackRate(qreal rate);
+ void updateAudioOutput(IBaseFilter *filter);
+
+ using QMediaPlayerControl::error;
+
+protected:
+ void customEvent(QEvent *event);
+
+private:
+ enum Properties
+ {
+ StateProperty = 0x01,
+ StatusProperty = 0x02,
+ StreamTypesProperty = 0x04,
+ DurationProperty = 0x08,
+ PlaybackRateProperty = 0x10,
+ SeekableProperty = 0x20
+ };
+
+ enum Event
+ {
+ PropertiesChanged = QEvent::User
+ };
+
+ void scheduleUpdate(int properties);
+
+ DirectShowPlayerService *m_service;
+ IBasicAudio *m_audio;
+ QIODevice *m_stream;
+ int m_updateProperties;
+ QMediaPlayer::State m_state;
+ QMediaPlayer::MediaStatus m_status;
+ int m_streamTypes;
+ int m_muteVolume;
+ qint64 m_duration;
+ qreal m_playbackRate;
+ bool m_seekable;
+ QMediaContent m_media;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp
new file mode 100644
index 0000000..ea4b73c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.cpp
@@ -0,0 +1,1235 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowplayerservice.h"
+
+#include "directshowaudioendpointcontrol.h"
+#include "directshowiosource.h"
+#include "directshowmetadatacontrol.h"
+#include "directshowplayercontrol.h"
+#include "directshowvideooutputcontrol.h"
+#include "directshowvideorenderercontrol.h"
+#include "vmr9videowindowcontrol.h"
+
+#include <QtMultimedia/qmediacontent.h>
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <uuids.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowPlayerServiceThread : public QThread
+{
+public:
+ DirectShowPlayerServiceThread(DirectShowPlayerService *service)
+ : m_service(service)
+ {
+ }
+
+protected:
+ void run() { m_service->run(); }
+
+private:
+ DirectShowPlayerService *m_service;
+};
+
+DirectShowPlayerService::DirectShowPlayerService(QObject *parent)
+ : QMediaService(parent)
+ , m_playerControl(0)
+ , m_audioEndpointControl(0)
+ , m_metaDataControl(0)
+ , m_videoOutputControl(0)
+ , m_videoRendererControl(0)
+ , m_videoWindowControl(0)
+ , m_taskThread(0)
+ , m_pendingTasks(0)
+ , m_executingTask(0)
+ , m_executedTasks(0)
+ , m_graphStatus(NoMedia)
+ , m_stream(0)
+ , m_graph(0)
+ , m_source(0)
+ , m_audioOutput(0)
+ , m_videoOutput(0)
+ , m_rate(1.0)
+ , m_position(0)
+ , m_duration(0)
+ , m_buffering(false)
+ , m_seekable(false)
+{
+ m_playerControl = new DirectShowPlayerControl(this);
+ m_metaDataControl = new DirectShowMetaDataControl(this);
+ m_videoOutputControl = new DirectShowVideoOutputControl;
+ m_audioEndpointControl = new DirectShowAudioEndpointControl(this);
+ m_videoRendererControl = new DirectShowVideoRendererControl(&m_loop);
+ m_videoWindowControl = new Vmr9VideoWindowControl;
+
+ m_taskThread = new DirectShowPlayerServiceThread(this);
+ m_taskThread->start();
+
+ connect(m_videoOutputControl, SIGNAL(outputChanged()), this, SLOT(videoOutputChanged()));
+ connect(m_videoRendererControl, SIGNAL(filterChanged()), this, SLOT(videoOutputChanged()));
+
+ connect(&m_graphEventNotifier, SIGNAL(activated(HANDLE)), this, SLOT(graphEvent(HANDLE)));
+}
+
+DirectShowPlayerService::~DirectShowPlayerService()
+{
+ {
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks = Shutdown;
+
+ if (m_graph) {
+ m_graphEventNotifier.setEnabled(false);
+
+ if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(m_graph)) {
+ progress->AbortOperation();
+ progress->Release();
+ }
+
+ m_graph->Abort();
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ OAFilterState state;
+ control->GetState(INFINITE, &state);
+ control->Release();
+ }
+ }
+ m_wait.wakeAll();
+
+ m_loop.wait(&m_mutex);
+ }
+
+ m_taskThread->wait();
+ delete m_taskThread;
+
+ if (m_graph) {
+ m_graph->Release();
+ m_graph = 0;
+ }
+
+ if (m_source) {
+ m_source->Release();
+ m_source = 0;
+ }
+
+ if (m_audioOutput) {
+ m_audioOutput->Release();
+ m_audioOutput = 0;
+ }
+
+ if (m_videoOutput) {
+ m_videoOutput->Release();
+ m_videoOutput = 0;
+ }
+
+ delete m_playerControl;
+ delete m_audioEndpointControl;
+ delete m_metaDataControl;
+ delete m_videoOutputControl;
+ delete m_videoRendererControl;
+ delete m_videoWindowControl;
+}
+
+QMediaControl *DirectShowPlayerService::control(const char *name) const
+{
+ if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
+ return m_playerControl;
+ else if (qstrcmp(name, QAudioEndpointSelector_iid) == 0)
+ return m_audioEndpointControl;
+ else if (qstrcmp(name, QMetaDataControl_iid) == 0)
+ return m_metaDataControl;
+ else if (qstrcmp(name, QVideoOutputControl_iid) == 0)
+ return m_videoOutputControl;
+ else if (qstrcmp(name, QVideoRendererControl_iid) == 0)
+ return m_videoRendererControl;
+ else if (qstrcmp(name, QVideoWindowControl_iid) == 0)
+ return m_videoWindowControl;
+ else
+ return 0;
+}
+
+void DirectShowPlayerService::load(const QMediaContent &media, QIODevice *stream)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_graph) {
+ m_graphEventNotifier.setEnabled(false);
+
+ if (m_executingTask != 0) {
+ if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(m_graph)) {
+ progress->AbortOperation();
+ progress->Release();
+ } else {
+ m_graph->Abort();
+ }
+
+ m_pendingTasks = Stop;
+
+ m_loop.wait(&m_mutex);
+ }
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ if (m_source) {
+ m_source->Release();
+ m_source = 0;
+ }
+
+ m_graph->Release();
+ m_graph = 0;
+ }
+
+ m_resources = media.resources();
+ m_stream = stream;
+ m_duration = 0;
+ m_streamTypes = 0;
+ m_executedTasks = 0;
+ m_buffering = false;
+ m_seekable = false;
+ m_metaDataControl->updateGraph(0, 0);
+
+ if (m_resources.isEmpty() && !stream) {
+ m_pendingTasks = 0;
+ m_graphStatus = NoMedia;
+
+ m_url.clear();
+ } else {
+ m_graphStatus = Loading;
+
+ m_graph = com_new<IFilterGraph2>(CLSID_FilterGraph);
+
+ if (IMediaEventEx *event = com_cast<IMediaEventEx>(m_graph)) {
+ HANDLE handle;
+ if (event->GetEventHandle(reinterpret_cast<OAEVENT *>(&handle)) == S_OK) {
+ m_graphEventNotifier.setHandle(handle);
+ m_graphEventNotifier.setEnabled(true);
+ }
+ event->Release();
+ }
+
+ if (stream)
+ m_pendingTasks = SetStreamSource;
+ else
+ m_pendingTasks = SetUrlSource;
+
+ m_wait.wakeAll();
+ }
+
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ updateStatus();
+}
+
+void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
+{
+ IBaseFilter *source = 0;
+
+ QMediaResource resource = m_resources.takeFirst();
+ QUrl url = resource.url();
+
+ HRESULT hr = E_FAIL;
+
+ if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https")) {
+ if (IFileSourceFilter *fileSource = com_new<IFileSourceFilter>(CLSID_WMAsfReader)) {
+ locker->unlock();
+ hr = fileSource->Load(url.toString().utf16(), 0);
+ locker->relock();
+
+ if (SUCCEEDED(hr)) {
+ source = com_cast<IBaseFilter>(fileSource);
+
+ if (!SUCCEEDED(hr = m_graph->AddFilter(source, L"Source")) && source) {
+ source->Release();
+ source = 0;
+ }
+ }
+
+ fileSource->Release();
+ }
+ }
+
+ if (!SUCCEEDED(hr)) {
+ locker->unlock();
+ hr = m_graph->AddSourceFilter(url.toString().utf16(), L"Source", &source);
+ locker->relock();
+ }
+
+ if (SUCCEEDED(hr)) {
+ m_executedTasks = SetSource;
+ m_pendingTasks |= Render;
+
+ if (m_audioOutput)
+ m_pendingTasks |= SetAudioOutput;
+ if (m_videoOutput)
+ m_pendingTasks |= SetVideoOutput;
+
+ if (m_rate != 1.0)
+ m_pendingTasks |= SetRate;
+
+ m_source = source;
+ } else if (!m_resources.isEmpty()) {
+ m_pendingTasks |= SetUrlSource;
+ } else {
+ m_pendingTasks = 0;
+ m_graphStatus = InvalidMedia;
+
+ switch (hr) {
+ case VFW_E_UNKNOWN_FILE_TYPE:
+ m_error = QMediaPlayer::FormatError;
+ break;
+ case E_OUTOFMEMORY:
+ case VFW_E_CANNOT_LOAD_SOURCE_FILTER:
+ case VFW_E_NOT_FOUND:
+ m_error = QMediaPlayer::ResourceError;
+ default:
+ m_error = QMediaPlayer::ResourceError;
+ qWarning("DirectShowPlayerService::doSetUrlSource: Unresolved error code %x", hr);
+ break;
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+}
+
+void DirectShowPlayerService::doSetStreamSource(QMutexLocker *locker)
+{
+ IBaseFilter *source = new DirectShowIOSource(m_stream, &m_loop);
+
+ if (SUCCEEDED(m_graph->AddFilter(source, L"Source"))) {
+ m_executedTasks = SetSource;
+ m_pendingTasks |= Render;
+
+ if (m_audioOutput)
+ m_pendingTasks |= SetAudioOutput;
+ if (m_videoOutput)
+ m_pendingTasks |= SetVideoOutput;
+
+ if (m_rate != 1.0)
+ m_pendingTasks |= SetRate;
+
+ m_source = source;
+ } else {
+ source->Release();
+
+ m_pendingTasks = 0;
+ m_graphStatus = InvalidMedia;
+
+ m_error = QMediaPlayer::ResourceError;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+}
+
+void DirectShowPlayerService::doRender(QMutexLocker *locker)
+{
+ if (m_pendingTasks & SetAudioOutput) {
+ m_graph->AddFilter(m_audioOutput, L"AudioOutput");
+
+ m_pendingTasks ^= SetAudioOutput;
+ m_executedTasks |= SetAudioOutput;
+ }
+ if (m_pendingTasks & SetVideoOutput) {
+ m_graph->AddFilter(m_videoOutput, L"VideoOutput");
+
+ m_pendingTasks ^= SetVideoOutput;
+ m_executedTasks |= SetVideoOutput;
+ }
+
+ IFilterGraph2 *graph = m_graph;
+ graph->AddRef();
+
+ QVarLengthArray<IBaseFilter *, 16> filters;
+ m_source->AddRef();
+ filters.append(m_source);
+
+ bool rendered = false;
+
+ HRESULT renderHr = S_OK;
+
+ while (!filters.isEmpty()) {
+ IEnumPins *pins = 0;
+ IBaseFilter *filter = filters[filters.size() - 1];
+ filters.removeLast();
+
+ if (m_executingTask == Render && SUCCEEDED(filter->EnumPins(&pins))) {
+ int outputs = 0;
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION direction;
+ if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) {
+ ++outputs;
+
+ IPin *peer = 0;
+ if (pin->ConnectedTo(&peer) == S_OK) {
+ PIN_INFO peerInfo;
+ if (peer->QueryPinInfo(&peerInfo) == S_OK)
+ filters.append(peerInfo.pFilter);
+ peer->Release();
+ } else {
+ locker->unlock();
+ HRESULT hr;
+ if (SUCCEEDED(hr = graph->RenderEx(
+ pin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, 0))) {
+ rendered = true;
+ } else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){
+ renderHr = hr;
+ }
+ locker->relock();
+ }
+ }
+ }
+ if (outputs == 0)
+ rendered = true;
+ }
+ filter->Release();
+ }
+
+
+ if (m_audioOutput && !isConnected(m_audioOutput, PINDIR_INPUT)) {
+ graph->RemoveFilter(m_audioOutput);
+
+ m_executedTasks &= ~SetAudioOutput;
+ }
+
+ if (m_videoOutput && !isConnected(m_videoOutput, PINDIR_INPUT)) {
+ graph->RemoveFilter(m_videoOutput);
+
+ m_executedTasks &= ~SetVideoOutput;
+ }
+
+ graph->Release();
+
+ if (m_executingTask == Render) {
+ if (rendered) {
+ if (!(m_executedTasks & FinalizeLoad))
+ m_pendingTasks |= FinalizeLoad;
+ } else {
+ m_pendingTasks = 0;
+
+ m_graphStatus = InvalidMedia;
+
+ if (!m_audioOutput && !m_videoOutput) {
+ m_error = QMediaPlayer::ResourceError;
+ } else {
+ switch (renderHr) {
+ case VFW_E_UNSUPPORTED_AUDIO:
+ case VFW_E_UNSUPPORTED_VIDEO:
+ case VFW_E_UNSUPPORTED_STREAM:
+ m_error = QMediaPlayer::FormatError;
+ default:
+ m_error = QMediaPlayer::ResourceError;
+ qWarning("DirectShowPlayerService::doRender: Unresolved error code %x",
+ renderHr);
+ }
+ }
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+
+ m_executedTasks |= Render;
+ }
+
+ m_loop.wake();
+}
+
+void DirectShowPlayerService::doFinalizeLoad(QMutexLocker *locker)
+{
+ if (m_graphStatus != Loaded) {
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG duration = 0;
+ seeking->GetDuration(&duration);
+ m_duration = duration / 10;
+
+ DWORD capabilities = 0;
+ seeking->GetCapabilities(&capabilities);
+ m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute;
+
+ seeking->Release();
+ }
+ }
+
+ if ((m_executedTasks & SetOutputs) == SetOutputs) {
+ m_streamTypes = AudioStream | VideoStream;
+ } else {
+ m_streamTypes = findStreamTypes(m_source);
+ }
+
+ m_executedTasks |= FinalizeLoad;
+
+ m_graphStatus = Loaded;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(FinalizedLoad)));
+}
+
+
+void DirectShowPlayerService::doUpdateDuration(QMutexLocker *)
+{
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG duration = 0;
+ seeking->GetDuration(&duration);
+ m_duration = duration / 10;
+
+ DWORD capabilities = 0;
+ seeking->GetCapabilities(&capabilities);
+ m_seekable = capabilities & AM_SEEKING_CanSeekAbsolute;
+
+ seeking->Release();
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(DurationChange)));
+ }
+}
+
+int DirectShowPlayerService::findStreamTypes(IBaseFilter *source) const
+{
+ QVarLengthArray<IBaseFilter *, 16> filters;
+ source->AddRef();
+ filters.append(source);
+
+ int streamTypes = 0;
+
+ while (!filters.isEmpty()) {
+ IEnumPins *pins = 0;
+ IBaseFilter *filter = filters[filters.size() - 1];
+ filters.removeLast();
+
+ if (SUCCEEDED(filter->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION direction;
+ if (pin->QueryDirection(&direction) == S_OK && direction == PINDIR_OUTPUT) {
+ AM_MEDIA_TYPE connectionType;
+ if (SUCCEEDED(pin->ConnectionMediaType(&connectionType))) {
+ IPin *peer = 0;
+
+ if (connectionType.majortype == MEDIATYPE_Audio) {
+ streamTypes |= AudioStream;
+ } else if (connectionType.majortype == MEDIATYPE_Video) {
+ streamTypes |= VideoStream;
+ } else if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ PIN_INFO peerInfo;
+ if (SUCCEEDED(peer->QueryPinInfo(&peerInfo)))
+ filters.append(peerInfo.pFilter);
+ peer->Release();
+ }
+ } else {
+ streamTypes |= findStreamType(pin);
+ }
+ }
+ }
+ }
+ filter->Release();
+ }
+ return streamTypes;
+}
+
+int DirectShowPlayerService::findStreamType(IPin *pin) const
+{
+ IEnumMediaTypes *types;
+
+ if (SUCCEEDED(pin->EnumMediaTypes(&types))) {
+ bool video = false;
+ bool audio = false;
+ bool other = false;
+
+ for (AM_MEDIA_TYPE *type = 0;
+ types->Next(1, &type, 0) == S_OK;
+ DirectShowMediaType::deleteType(type)) {
+ if (type->majortype == MEDIATYPE_Audio)
+ audio = true;
+ else if (type->majortype == MEDIATYPE_Video)
+ video = true;
+ else
+ other = true;
+ }
+ types->Release();
+
+ if (other)
+ return 0;
+ else if (audio && !video)
+ return AudioStream;
+ else if (!audio && video)
+ return VideoStream;
+ else
+ return 0;
+ } else {
+ return 0;
+ }
+}
+
+void DirectShowPlayerService::play()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~Pause;
+ m_pendingTasks |= Play;
+
+ if (m_executedTasks & Render) {
+ if (m_executedTasks & Stop) {
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ m_executedTasks ^= Stop;
+ }
+
+ m_wait.wakeAll();
+ }
+}
+
+void DirectShowPlayerService::doPlay(QMutexLocker *locker)
+{
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ locker->unlock();
+ HRESULT hr = control->Run();
+ locker->relock();
+
+ control->Release();
+
+ if (SUCCEEDED(hr))
+ m_executedTasks |= Play;
+
+ if (SUCCEEDED(hr)) {
+ m_executedTasks |= Play;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Started)));
+ } else {
+ m_error = QMediaPlayer::ResourceError;
+ qWarning("DirectShowPlayerService::doPlay: Unresolved error code %x", hr);
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+ }
+}
+
+void DirectShowPlayerService::pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~Play;
+ m_pendingTasks |= Pause;
+
+ if (m_executedTasks & Render) {
+ if (m_executedTasks & Stop) {
+ m_position = 0;
+ m_pendingTasks |= Seek;
+ m_executedTasks ^= Stop;
+ }
+
+ m_wait.wakeAll();
+ }
+}
+
+void DirectShowPlayerService::doPause(QMutexLocker *locker)
+{
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ locker->unlock();
+ HRESULT hr = control->Pause();
+ locker->relock();
+
+ control->Release();
+
+ if (SUCCEEDED(hr)) {
+ m_executedTasks |= Pause;
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Paused)));
+ } else {
+ m_error = QMediaPlayer::ResourceError;
+ qWarning("DirectShowPlayerService::doPause: Unresolved error code %x", hr);
+
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ }
+ }
+}
+
+void DirectShowPlayerService::stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_pendingTasks &= ~(Play | Pause | Seek);
+
+ if (m_executedTasks & Render) {
+ if (m_executingTask & (Play | Pause | Seek)) {
+ m_pendingTasks |= Stop;
+
+ m_loop.wait(&m_mutex);
+ }
+
+ if (m_executedTasks & (Play | Pause)) {
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+ m_executedTasks &= ~(Play | Pause);
+ }
+ }
+
+ m_executedTasks |= Stop;
+}
+
+void DirectShowPlayerService::setRate(qreal rate)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_rate = rate;
+
+ m_pendingTasks |= SetRate;
+
+ if (m_executedTasks & FinalizeLoad)
+ m_wait.wakeAll();
+}
+
+void DirectShowPlayerService::doSetRate(QMutexLocker *locker)
+{
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ // Cache current values as we can't query IMediaSeeking during a seek due to the
+ // possibility of a deadlock when flushing the VideoSurfaceFilter.
+ LONGLONG currentPosition = 0;
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / 10;
+
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+ m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum))
+ ? QMediaTimeRange(minimum / 10, maximum / 10)
+ : QMediaTimeRange();
+
+ locker->unlock();
+ HRESULT hr = seeking->SetRate(m_rate);
+ locker->relock();
+
+ if (!SUCCEEDED(hr)) {
+ double rate = 0.0;
+ m_rate = seeking->GetRate(&rate)
+ ? rate
+ : 1.0;
+ }
+
+ seeking->Release();
+ } else if (m_rate != 1.0) {
+ m_rate = 1.0;
+ }
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(RateChange)));
+}
+
+qint64 DirectShowPlayerService::position() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (m_graphStatus == Loaded) {
+ if (m_executingTask == Seek || m_executingTask == SetRate) {
+ return m_position;
+ } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG position = 0;
+
+ seeking->GetCurrentPosition(&position);
+ seeking->Release();
+
+ return position / 10;
+ }
+ }
+ return 0;
+}
+
+QMediaTimeRange DirectShowPlayerService::availablePlaybackRanges() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (m_graphStatus == Loaded) {
+ if (m_executingTask == Seek || m_executingTask == SetRate) {
+ return m_playbackRange;
+ } else if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+
+ HRESULT hr = seeking->GetAvailable(&minimum, &maximum);
+ seeking->Release();
+
+ if (SUCCEEDED(hr))
+ return QMediaTimeRange(minimum, maximum);
+ }
+ }
+ return QMediaTimeRange();
+}
+
+void DirectShowPlayerService::seek(qint64 position)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_position = position;
+
+ m_pendingTasks |= Seek;
+
+ if (m_executedTasks & FinalizeLoad)
+ m_wait.wakeAll();
+}
+
+void DirectShowPlayerService::doSeek(QMutexLocker *locker)
+{
+ if (IMediaSeeking *seeking = com_cast<IMediaSeeking>(m_graph)) {
+ LONGLONG seekPosition = LONGLONG(m_position) * 10;
+
+ // Cache current values as we can't query IMediaSeeking during a seek due to the
+ // possibility of a deadlock when flushing the VideoSurfaceFilter.
+ LONGLONG currentPosition = 0;
+ seeking->GetCurrentPosition(&currentPosition);
+ m_position = currentPosition / 10;
+
+ LONGLONG minimum = 0;
+ LONGLONG maximum = 0;
+ m_playbackRange = SUCCEEDED(seeking->GetAvailable(&minimum, &maximum))
+ ? QMediaTimeRange(minimum / 10, maximum / 10)
+ : QMediaTimeRange();
+
+ locker->unlock();
+ seeking->SetPositions(
+ &seekPosition, AM_SEEKING_AbsolutePositioning, 0, AM_SEEKING_NoPositioning);
+ locker->relock();
+
+ seeking->Release();
+ }
+}
+
+int DirectShowPlayerService::bufferStatus() const
+{
+ QMutexLocker locker(const_cast<QMutex *>(&m_mutex));
+
+ if (IWMReaderAdvanced2 *reader = com_cast<IWMReaderAdvanced2>(m_source)) {
+ DWORD percentage = 0;
+
+ reader->GetBufferProgress(&percentage, 0);
+ reader->Release();
+
+ return percentage;
+ } else {
+ return 0;
+ }
+}
+
+void DirectShowPlayerService::setAudioOutput(IBaseFilter *filter)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_graph) {
+ if (m_audioOutput) {
+ if (m_executedTasks & SetAudioOutput) {
+ removeOutput(m_audioOutput);
+
+ m_executedTasks &= ~SetAudioOutput;
+ }
+ m_audioOutput->Release();
+ }
+
+ m_audioOutput = filter;
+
+ if (m_audioOutput) {
+ m_audioOutput->AddRef();
+
+ m_pendingTasks |= SetAudioOutput;
+ } else {
+ m_pendingTasks &= ~ SetAudioOutput;
+ }
+
+ if (m_executedTasks & SetSource) {
+ m_pendingTasks |= Render;
+
+ m_wait.wakeAll();
+ }
+ } else {
+ if (m_audioOutput)
+ m_audioOutput->Release();
+
+ m_audioOutput = filter;
+
+ if (m_audioOutput)
+ m_audioOutput->AddRef();
+ }
+
+ m_playerControl->updateAudioOutput(m_audioOutput);
+}
+
+void DirectShowPlayerService::setVideoOutput(IBaseFilter *filter)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_graph) {
+ if (m_videoOutput) {
+ if (m_executedTasks & SetVideoOutput) {
+ removeOutput(m_videoOutput);
+
+ m_executedTasks &= ~SetVideoOutput;
+ }
+ m_videoOutput->Release();
+ }
+
+ m_videoOutput = filter;
+
+ if (m_videoOutput) {
+ m_videoOutput->AddRef();
+
+ m_pendingTasks |= SetVideoOutput;
+ } else {
+ m_pendingTasks &= ~ SetVideoOutput;
+ }
+
+ if (m_executedTasks & SetSource) {
+ m_pendingTasks |= Render;
+
+ m_wait.wakeAll();
+ }
+ } else {
+ if (m_videoOutput)
+ m_videoOutput->Release();
+
+ m_videoOutput = filter;
+
+ if (m_videoOutput)
+ m_videoOutput->AddRef();
+ }
+}
+
+void DirectShowPlayerService::customEvent(QEvent *event)
+{
+ if (event->type() == QEvent::Type(FinalizedLoad)) {
+ event->accept();
+
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_metaDataControl->updateGraph(m_graph, m_source);
+
+ updateStatus();
+ } else if (event->type() == QEvent::Type(Error)) {
+ event->accept();
+
+ QMediaPlayer::Error error;
+ {
+ QMutexLocker locker(&m_mutex);
+ error = m_error;
+
+ if (error != QMediaPlayer::NoError) {
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ updateStatus();
+ }
+ }
+ m_playerControl->error(error, QString());
+ } else if (event->type() == QEvent::Type(RateChange)) {
+ event->accept();
+
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updatePlaybackRate(m_rate);
+ } else if (event->type() == QEvent::Type(Started) || event->type() == QEvent::Type(Paused)) {
+ event->accept();
+
+ QMutexLocker locker(&m_mutex);
+
+ updateStatus();
+ } else if (event->type() == QEvent::Type(DurationChange)) {
+ event->accept();
+
+ QMutexLocker locker(&m_mutex);
+
+ m_playerControl->updateMediaInfo(m_duration, m_streamTypes, m_seekable);
+ } else {
+ QMediaService::customEvent(event);
+ }
+}
+
+void DirectShowPlayerService::videoOutputChanged()
+{
+ IBaseFilter *videoOutput = 0;
+
+ switch (m_videoOutputControl->output()) {
+ case QVideoOutputControl::RendererOutput:
+ videoOutput = m_videoRendererControl->filter();
+ break;
+ case QVideoOutputControl::WindowOutput:
+ videoOutput = m_videoWindowControl->filter();
+ break;
+ default:
+ break;
+ }
+
+ setVideoOutput(videoOutput);
+}
+
+void DirectShowPlayerService::graphEvent(HANDLE handle)
+{
+ if (IMediaEvent *event = com_cast<IMediaEvent>(m_graph)) {
+ long eventCode;
+ LONG_PTR param1;
+ LONG_PTR param2;
+
+ while (event->GetEvent(&eventCode, &param1, &param2, 0) == S_OK) {
+ switch (eventCode) {
+ case EC_BUFFERING_DATA:
+ {
+ QMutexLocker locker(&m_mutex);
+ m_buffering = param1;
+
+ updateStatus();
+ }
+ break;
+ case EC_COMPLETE:
+ {
+ QMutexLocker locker(&m_mutex);
+ m_executedTasks &= ~(Play | Pause);
+ m_executedTasks |= Stop;
+
+ m_buffering = false;
+ m_playerControl->updateStatus(QMediaPlayer::EndOfMedia);
+ m_playerControl->updateState(QMediaPlayer::StoppedState);
+ }
+ break;
+ case EC_LENGTH_CHANGED:
+ {
+ QMutexLocker locker(&m_mutex);
+ if (m_executedTasks & FinalizeLoad) {
+ m_pendingTasks |= UpdateDuration;
+
+ m_wait.wakeAll();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ event->FreeEventParams(eventCode, param1, param2);
+ }
+ event->Release();
+ }
+}
+
+void DirectShowPlayerService::updateStatus()
+{
+ switch (m_graphStatus) {
+ case NoMedia:
+ m_playerControl->updateStatus(QMediaPlayer::NoMedia);
+ break;
+ case Loading:
+ m_playerControl->updateStatus(QMediaPlayer::LoadingMedia);
+ break;
+ case Loaded:
+ if ((m_pendingTasks | m_executingTask | m_executedTasks) & (Play | Pause)) {
+ if (m_buffering)
+ m_playerControl->updateStatus(QMediaPlayer::BufferingMedia);
+ else
+ m_playerControl->updateStatus(QMediaPlayer::BufferedMedia);
+ } else {
+ m_playerControl->updateStatus(QMediaPlayer::LoadedMedia);
+ }
+ break;
+ case InvalidMedia:
+ m_playerControl->updateStatus(QMediaPlayer::InvalidMedia);
+ break;
+ default:
+ m_playerControl->updateStatus(QMediaPlayer::UnknownMediaStatus);
+ }
+}
+
+void DirectShowPlayerService::removeOutput(IBaseFilter *output)
+{
+ while (m_executingTask != 0) {
+ if (m_executingTask == Render) {
+ m_executingTask = 0;
+
+ if (IAMOpenProgress *progress = com_cast<IAMOpenProgress>(m_graph)) {
+ progress->AbortOperation();
+ progress->Release();
+ }
+ }
+ m_loop.wait(&m_mutex);
+ }
+
+ m_pendingTasks |= m_executedTasks & (Play | Pause);
+
+ if (IMediaControl *control = com_cast<IMediaControl>(m_graph)) {
+ control->Stop();
+ control->Release();
+ }
+
+ if (IFilterChain *chain = com_cast<IFilterChain>(m_graph)) {
+ IBaseFilter *start = findChainStart(output);
+
+ chain->RemoveChain(start, output);
+
+ start->Release();
+ chain->Release();
+ } else {
+ m_graph->RemoveFilter(output);
+ }
+}
+
+IBaseFilter *DirectShowPlayerService::findChainStart(IBaseFilter *end) const
+{
+ IBaseFilter *start = 0;
+ end->AddRef();
+
+ while (start != end) {
+ start = end;
+
+ IEnumPins *pins = 0;
+
+ if (SUCCEEDED(end->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION direction;
+ if (SUCCEEDED(pin->QueryDirection(&direction)) && direction == PINDIR_INPUT) {
+ IPin *peer = 0;
+ if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ PIN_INFO peerInfo;
+ if (SUCCEEDED(peer->QueryPinInfo(&peerInfo))) {
+ CLSID classId;
+ if (SUCCEEDED(peerInfo.pFilter->GetClassID(&classId))
+ && classId == CLSID_Colour) {
+ end->Release();
+ end = peerInfo.pFilter;
+ } else {
+ peerInfo.pFilter->Release();
+ }
+ }
+ peer->Release();
+ }
+ }
+ }
+ pins->Release();
+ }
+ }
+ return start;
+}
+
+bool DirectShowPlayerService::isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const
+{
+ bool connected = false;
+
+ IEnumPins *pins = 0;
+
+ if (SUCCEEDED(filter->EnumPins(&pins))) {
+ for (IPin *pin = 0; pins->Next(1, &pin, 0) == S_OK; pin->Release()) {
+ PIN_DIRECTION dir;
+ if (SUCCEEDED(pin->QueryDirection(&dir)) && dir == direction) {
+ IPin *peer = 0;
+ if (SUCCEEDED(pin->ConnectedTo(&peer))) {
+ connected = true;
+
+ peer->Release();
+ }
+ }
+ }
+ pins->Release();
+ }
+ return connected;
+}
+
+void DirectShowPlayerService::run()
+{
+ QMutexLocker locker(&m_mutex);
+
+ while (!(m_pendingTasks & Shutdown)) {
+ if (m_pendingTasks & SetUrlSource) {
+ m_pendingTasks ^= SetUrlSource;
+ m_executingTask = SetUrlSource;
+
+ doSetUrlSource(&locker);
+ } else if (m_pendingTasks & SetStreamSource) {
+ m_pendingTasks ^= SetStreamSource;
+ m_executingTask = SetStreamSource;
+
+ doSetStreamSource(&locker);
+ } else if (m_pendingTasks & Render) {
+ m_pendingTasks ^= Render;
+ m_executingTask = Render;
+
+ doRender(&locker);
+ } else if (!(m_executedTasks & Render)) {
+ m_pendingTasks &= ~(FinalizeLoad | SetRate | Stop | Pause | Seek | Play);
+ } else if (m_pendingTasks & FinalizeLoad) {
+ m_pendingTasks ^= FinalizeLoad;
+ m_executingTask = FinalizeLoad;
+
+ doFinalizeLoad(&locker);
+ } else if (m_pendingTasks & UpdateDuration) {
+ m_pendingTasks ^= UpdateDuration;
+ m_executingTask ^= UpdateDuration;
+
+ doUpdateDuration(&locker);
+ } else if (m_pendingTasks & SetRate) {
+ m_pendingTasks ^= SetRate;
+ m_executingTask = SetRate;
+
+ doSetRate(&locker);
+ } else if (m_pendingTasks & Stop) {
+ m_pendingTasks ^= Stop;
+
+ m_loop.wake();
+ } else if (m_pendingTasks & Pause) {
+ m_pendingTasks ^= Pause;
+ m_executingTask = Pause;
+
+ doPause(&locker);
+ } else if (m_pendingTasks & Seek) {
+ m_pendingTasks ^= Seek;
+ m_executingTask = Seek;
+
+ doSeek(&locker);
+ } else if (m_pendingTasks & Play) {
+ m_pendingTasks ^= Play;
+ m_executingTask = Play;
+
+ doPlay(&locker);
+ }
+ m_executingTask = 0;
+
+ if (m_pendingTasks == 0)
+ m_wait.wait(&m_mutex);
+ }
+
+ m_loop.wake();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h
new file mode 100644
index 0000000..3a01889
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowplayerservice.h
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWPLAYERSERVICE_H
+#define DIRECTSHOWPLAYERSERVICE_H
+
+#include <QtMultimedia/qmediaplayer.h>
+#include <QtMultimedia/qmediaresource.h>
+#include <QtMultimedia/qmediaservice.h>
+#include <QtMultimedia/qmediatimerange.h>
+
+#include "directshoweventloop.h"
+#include "directshowglobal.h"
+
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <QtCore/private/qwineventnotifier_p.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowAudioEndpointControl;
+class DirectShowMetaDataControl;
+class DirectShowPlayerControl;
+class DirectShowVideoOutputControl;
+class DirectShowVideoRendererControl;
+class Vmr9VideoWindowControl;
+
+class DirectShowPlayerService : public QMediaService
+{
+ Q_OBJECT
+public:
+ enum StreamType
+ {
+ AudioStream = 0x01,
+ VideoStream = 0x02
+ };
+
+ DirectShowPlayerService(QObject *parent = 0);
+ ~DirectShowPlayerService();
+
+ QMediaControl* control(const char *name) const;
+
+ void load(const QMediaContent &media, QIODevice *stream);
+ void play();
+ void pause();
+ void stop();
+
+ qint64 position() const;
+ QMediaTimeRange availablePlaybackRanges() const;
+
+ void seek(qint64 position);
+ void setRate(qreal rate);
+
+ int bufferStatus() const;
+
+ void setAudioOutput(IBaseFilter *filter);
+ void setVideoOutput(IBaseFilter *filter);
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void videoOutputChanged();
+ void graphEvent(HANDLE handle);
+
+private:
+ void updateStatus();
+
+ int findStreamTypes(IBaseFilter *source) const;
+ int findStreamType(IPin *pin) const;
+
+ void removeOutput(IBaseFilter *output);
+ IBaseFilter *findChainStart(IBaseFilter *end) const;
+ bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const;
+
+ void run();
+
+ void doSetUrlSource(QMutexLocker *locker);
+ void doSetStreamSource(QMutexLocker *locker);
+ void doRender(QMutexLocker *locker);
+ void doFinalizeLoad(QMutexLocker *locker);
+ void doSetRate(QMutexLocker *locker);
+ void doSeek(QMutexLocker *locker);
+ void doPlay(QMutexLocker *locker);
+ void doPause(QMutexLocker *locker);
+ void doUpdateDuration(QMutexLocker *locker);
+
+ enum Task
+ {
+ Shutdown = 0x0001,
+ SetUrlSource = 0x0002,
+ SetStreamSource = 0x0004,
+ SetSource = SetUrlSource | SetStreamSource,
+ SetAudioOutput = 0x0008,
+ SetVideoOutput = 0x0010,
+ SetOutputs = SetAudioOutput | SetVideoOutput,
+ Render = 0x0020,
+ FinalizeLoad = 0x0040,
+ SetRate = 0x0080,
+ Seek = 0x0100,
+ Play = 0x0200,
+ Pause = 0x0400,
+ Stop = 0x0800,
+ UpdateDuration = 0x1000
+ };
+
+ enum Event
+ {
+ FinalizedLoad = QEvent::User,
+ Error,
+ RateChange,
+ Started,
+ Paused,
+ DurationChange
+ };
+
+ enum GraphStatus
+ {
+ NoMedia,
+ Loading,
+ Loaded,
+ InvalidMedia
+ };
+
+ DirectShowPlayerControl *m_playerControl;
+ DirectShowMetaDataControl *m_metaDataControl;
+ DirectShowVideoOutputControl *m_videoOutputControl;
+ DirectShowVideoRendererControl *m_videoRendererControl;
+ Vmr9VideoWindowControl *m_videoWindowControl;
+ DirectShowAudioEndpointControl *m_audioEndpointControl;
+
+ QThread *m_taskThread;
+ int m_pendingTasks;
+ int m_executingTask;
+ int m_executedTasks;
+ GraphStatus m_graphStatus;
+ QMediaPlayer::Error m_error;
+ QIODevice *m_stream;
+ IFilterGraph2 *m_graph;
+ IBaseFilter *m_source;
+ IBaseFilter *m_audioOutput;
+ IBaseFilter *m_videoOutput;
+ int m_streamTypes;
+ qreal m_rate;
+ qint64 m_position;
+ qint64 m_duration;
+ bool m_buffering;
+ bool m_seekable;
+ QMediaTimeRange m_playbackRange;
+ QUrl m_url;
+ QMediaResourceList m_resources;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+ QWinEventNotifier m_graphEventNotifier;
+ DirectShowEventLoop m_loop;
+
+ friend class DirectShowPlayerServiceThread;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp
new file mode 100644
index 0000000..921330c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.cpp
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowsamplescheduler.h"
+
+#include <QtCore/qcoreevent.h>
+
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowTimedSample
+{
+public:
+ DirectShowTimedSample(IMediaSample *sample)
+ : m_next(0)
+ , m_sample(sample)
+ , m_cookie(0)
+ {
+ m_sample->AddRef();
+ }
+
+ ~DirectShowTimedSample()
+ {
+ m_sample->Release();
+ }
+
+ IMediaSample *sample() const { return m_sample; }
+
+ DirectShowTimedSample *nextSample() const { return m_next; }
+ void setNextSample(DirectShowTimedSample *sample) { Q_ASSERT(!m_next); m_next = sample; }
+
+ DirectShowTimedSample *remove() {
+ DirectShowTimedSample *next = m_next; delete this; return next; }
+
+ bool schedule(IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle);
+ void unschedule(IReferenceClock *clock);
+
+ bool isReady(IReferenceClock *clock) const;
+
+private:
+ DirectShowTimedSample *m_next;
+ IMediaSample *m_sample;
+ DWORD_PTR m_cookie;
+};
+
+bool DirectShowTimedSample::schedule(
+ IReferenceClock *clock, REFERENCE_TIME startTime, HANDLE handle)
+{
+ REFERENCE_TIME sampleStartTime;
+ REFERENCE_TIME sampleEndTime;
+ if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) {
+ if (clock->AdviseTime(
+ startTime, sampleStartTime, reinterpret_cast<HEVENT>(handle), &m_cookie) == S_OK) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void DirectShowTimedSample::unschedule(IReferenceClock *clock)
+{
+ clock->Unadvise(m_cookie);
+}
+
+bool DirectShowTimedSample::isReady(IReferenceClock *clock) const
+{
+ REFERENCE_TIME sampleStartTime;
+ REFERENCE_TIME sampleEndTime;
+ REFERENCE_TIME currentTime;
+ if (m_sample->GetTime(&sampleStartTime, &sampleEndTime) == S_OK) {
+ if (clock->GetTime(&currentTime) == S_OK)
+ return currentTime >= sampleStartTime;
+ }
+ return true;
+}
+
+DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent)
+ : QWinEventNotifier(parent)
+ , m_pin(pin)
+ , m_clock(0)
+ , m_allocator(0)
+ , m_head(0)
+ , m_tail(0)
+ , m_maximumSamples(2)
+ , m_state(Stopped)
+ , m_startTime(0)
+ , m_timeoutEvent(::CreateEvent(0, 0, 0, 0))
+{
+ m_semaphore.release(m_maximumSamples);
+
+ setHandle(m_timeoutEvent);
+ setEnabled(true);
+}
+
+DirectShowSampleScheduler::~DirectShowSampleScheduler()
+{
+ setEnabled(false);
+
+ ::CloseHandle(m_timeoutEvent);
+
+ Q_ASSERT(!m_clock);
+ Q_ASSERT(!m_allocator);
+}
+
+HRESULT DirectShowSampleScheduler::QueryInterface(REFIID riid, void **ppvObject)
+{
+ return m_pin->QueryInterface(riid, ppvObject);
+}
+
+ULONG DirectShowSampleScheduler::AddRef()
+{
+ return m_pin->AddRef();
+}
+
+ULONG DirectShowSampleScheduler::Release()
+{
+ return m_pin->Release();
+}
+
+// IMemInputPin
+HRESULT DirectShowSampleScheduler::GetAllocator(IMemAllocator **ppAllocator)
+{
+ if (!ppAllocator) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_allocator) {
+ return VFW_E_NO_ALLOCATOR;
+ } else {
+ *ppAllocator = m_allocator;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT DirectShowSampleScheduler::NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly)
+{
+ Q_UNUSED(bReadOnly);
+
+ HRESULT hr;
+ ALLOCATOR_PROPERTIES properties;
+
+ if (!pAllocator) {
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = 0;
+
+ return S_OK;
+ } else if ((hr = pAllocator->GetProperties(&properties)) != S_OK) {
+ return hr;
+ } else {
+ if (properties.cBuffers == 1) {
+ ALLOCATOR_PROPERTIES actual;
+
+ properties.cBuffers = 2;
+ if ((hr = pAllocator->SetProperties(&properties, &actual)) != S_OK)
+ return hr;
+ }
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_allocator)
+ m_allocator->Release();
+
+ m_allocator = pAllocator;
+ m_allocator->AddRef();
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowSampleScheduler::GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps)
+{
+ if (!pProps)
+ return E_POINTER;
+
+ pProps->cBuffers = 2;
+
+ return S_OK;
+}
+
+HRESULT DirectShowSampleScheduler::Receive(IMediaSample *pSample)
+{
+ if (!pSample)
+ return E_POINTER;
+
+ m_semaphore.acquire(1);
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_state & Flushing) {
+ m_semaphore.release(1);
+
+ return S_FALSE;
+ } else if (m_state == Stopped) {
+ m_semaphore.release();
+
+ return VFW_E_WRONG_STATE;
+ } else {
+ DirectShowTimedSample *timedSample = new DirectShowTimedSample(pSample);
+
+ if (m_tail)
+ m_tail->setNextSample(timedSample);
+ else
+ m_head = timedSample;
+
+ m_tail = timedSample;
+
+ if (m_state == Running) {
+ if (!timedSample->schedule(m_clock, m_startTime, m_timeoutEvent)) {
+ // Timing information is unavailable, so schedule frames immediately.
+ QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection);
+ }
+ } else if (m_tail == m_head) {
+ // If this is the first frame make is available.
+ QMetaObject::invokeMethod(this, "timerActivated", Qt::QueuedConnection);
+ }
+
+ return S_OK;
+ }
+}
+
+HRESULT DirectShowSampleScheduler::ReceiveMultiple(
+ IMediaSample **pSamples, long nSamples, long *nSamplesProcessed)
+{
+ if (!pSamples || !nSamplesProcessed)
+ return E_POINTER;
+
+ for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; ++(*nSamplesProcessed)) {
+ HRESULT hr = Receive(pSamples[*nSamplesProcessed]);
+
+ if (hr != S_OK)
+ return hr;
+ }
+ return S_OK;
+}
+
+HRESULT DirectShowSampleScheduler::ReceiveCanBlock()
+{
+ return S_OK;
+}
+
+void DirectShowSampleScheduler::run(REFERENCE_TIME startTime)
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = (m_state & Flushing) | Running;
+ m_startTime = startTime;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample()) {
+ sample->schedule(m_clock, m_startTime, m_timeoutEvent);
+ }
+}
+
+void DirectShowSampleScheduler::pause()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = (m_state & Flushing) | Paused;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->nextSample())
+ sample->unschedule(m_clock);
+}
+
+void DirectShowSampleScheduler::stop()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_state = m_state & Flushing;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) {
+ sample->unschedule(m_clock);
+
+ m_semaphore.release(1);
+ }
+
+ m_head = 0;
+ m_tail = 0;
+}
+
+void DirectShowSampleScheduler::setFlushing(bool flushing)
+{
+ QMutexLocker locker(&m_mutex);
+
+ const bool isFlushing = m_state & Flushing;
+
+ if (isFlushing != flushing) {
+ if (flushing) {
+ m_state |= Flushing;
+
+ for (DirectShowTimedSample *sample = m_head; sample; sample = sample->remove()) {
+ sample->unschedule(m_clock);
+
+ m_semaphore.release(1);
+ }
+ m_head = 0;
+ m_tail = 0;
+ } else {
+ m_state &= ~Flushing;
+ }
+ }
+}
+
+void DirectShowSampleScheduler::setClock(IReferenceClock *clock)
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_clock)
+ m_clock->Release();
+
+ m_clock = clock;
+
+ if (m_clock)
+ m_clock->AddRef();
+}
+
+IMediaSample *DirectShowSampleScheduler::takeSample()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (m_head && m_head->isReady(m_clock)) {
+ IMediaSample *sample = m_head->sample();
+ sample->AddRef();
+
+ if (m_state == Running) {
+ m_head = m_head->remove();
+
+ if (!m_head)
+ m_tail = 0;
+
+ m_semaphore.release(1);
+ }
+
+ return sample;
+ } else {
+ return 0;
+ }
+}
+
+bool DirectShowSampleScheduler::event(QEvent *event)
+{
+ if (event->type() == QEvent::WinEventAct) {
+ QObject::event(event);
+
+ emit sampleReady();
+
+ return true;
+ } else {
+ return QWinEventNotifier::event(event);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h
new file mode 100644
index 0000000..7af9112
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowsamplescheduler.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWSAMPLESCHEDULER_H
+#define DIRECTSHOWSAMPLESCHEDULER_H
+
+#include <QtCore/qmutex.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qsemaphore.h>
+
+#include <QtCore/private/qwineventnotifier_p.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowTimedSample;
+
+class DirectShowSampleScheduler : public QWinEventNotifier, public IMemInputPin
+{
+ Q_OBJECT
+public:
+
+ enum State
+ {
+ Stopped = 0x00,
+ Running = 0x01,
+ Paused = 0x02,
+ RunMask = 0x03,
+ Flushing = 0x04
+ };
+
+ DirectShowSampleScheduler(IUnknown *pin, QObject *parent = 0);
+ ~DirectShowSampleScheduler();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IMemInputPin
+ HRESULT STDMETHODCALLTYPE GetAllocator(IMemAllocator **ppAllocator);
+ HRESULT STDMETHODCALLTYPE NotifyAllocator(IMemAllocator *pAllocator, BOOL bReadOnly);
+ HRESULT STDMETHODCALLTYPE GetAllocatorRequirements(ALLOCATOR_PROPERTIES *pProps);
+
+ HRESULT STDMETHODCALLTYPE Receive(IMediaSample *pSample);
+ HRESULT STDMETHODCALLTYPE ReceiveMultiple(IMediaSample **pSamples, long nSamples, long *nSamplesProcessed);
+ HRESULT STDMETHODCALLTYPE ReceiveCanBlock();
+
+ void run(REFERENCE_TIME startTime);
+ void pause();
+ void stop();
+ void setFlushing(bool flushing);
+
+ IReferenceClock *clock() const { return m_clock; }
+ void setClock(IReferenceClock *clock);
+
+ bool schedule(IMediaSample *sample);
+
+ IMediaSample *takeSample();
+
+ bool event(QEvent *event);
+
+Q_SIGNALS:
+ void sampleReady();
+
+private:
+ IUnknown *m_pin;
+ IReferenceClock *m_clock;
+ IMemAllocator *m_allocator;
+ DirectShowTimedSample *m_head;
+ DirectShowTimedSample *m_tail;
+ int m_maximumSamples;
+ int m_state;
+ REFERENCE_TIME m_startTime;
+ HANDLE m_timeoutEvent;
+ QSemaphore m_semaphore;
+ QMutex m_mutex;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp
new file mode 100644
index 0000000..ee2bea8
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowvideooutputcontrol.h"
+
+
+QT_BEGIN_NAMESPACE
+
+DirectShowVideoOutputControl::DirectShowVideoOutputControl(QObject *parent)
+ : QVideoOutputControl(parent)
+ , m_output(NoOutput)
+{
+
+}
+
+DirectShowVideoOutputControl::~DirectShowVideoOutputControl()
+{
+}
+
+QList<QVideoOutputControl::Output> DirectShowVideoOutputControl::availableOutputs() const
+{
+ return QList<Output>()
+ << RendererOutput
+ << WindowOutput;
+}
+
+
+QVideoOutputControl::Output DirectShowVideoOutputControl::output() const
+{
+ return m_output;
+}
+
+void DirectShowVideoOutputControl::setOutput(Output output)
+{
+ if (output != m_output) {
+ switch (output) {
+ case NoOutput:
+ case RendererOutput:
+ case WindowOutput:
+ m_output = output;
+ emit outputChanged();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h
new file mode 100644
index 0000000..acb2937
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideooutputcontrol.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWVIDEOUTPUTCONTROL_H
+#define DIRECTSHOWVIDEOOUPUTCONTROL_H
+
+#include <QtMultimedia/qvideooutputcontrol.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowVideoOutputControl : public QVideoOutputControl
+{
+ Q_OBJECT
+public:
+ DirectShowVideoOutputControl(QObject *parent = 0);
+ ~DirectShowVideoOutputControl();
+
+ QList<Output> availableOutputs() const;
+
+ Output output() const;
+ void setOutput(Output output);
+
+Q_SIGNALS:
+ void outputChanged();
+
+private:
+ Output m_output;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp
new file mode 100644
index 0000000..f27cb10
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "directshowvideorenderercontrol.h"
+
+#include "videosurfacefilter.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+DirectShowVideoRendererControl::DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_loop(loop)
+ , m_surface(0)
+ , m_filter(0)
+{
+}
+
+DirectShowVideoRendererControl::~DirectShowVideoRendererControl()
+{
+ delete m_filter;
+}
+
+QAbstractVideoSurface *DirectShowVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void DirectShowVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (surface != m_surface) {
+ m_surface = surface;
+
+ VideoSurfaceFilter *existingFilter = m_filter;
+
+ if (surface) {
+ m_filter = new VideoSurfaceFilter(surface, m_loop);
+ } else {
+ m_filter = 0;
+ }
+
+ emit filterChanged();
+
+ delete existingFilter;
+ }
+}
+
+IBaseFilter *DirectShowVideoRendererControl::filter()
+{
+ return m_filter;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h
new file mode 100644
index 0000000..6b4f4a2
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/directshowvideorenderercontrol.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DIRECTSHOWVIDEORENDERERCONTROL_H
+#define DIRECTSHOWVIDEORENDERERCONTROL_H
+
+#include <QtMultimedia/qvideorenderercontrol.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class DirectShowEventLoop;
+class VideoSurfaceFilter;
+
+class DirectShowVideoRendererControl : public QVideoRendererControl
+{
+ Q_OBJECT
+public:
+ DirectShowVideoRendererControl(DirectShowEventLoop *loop, QObject *parent = 0);
+ ~DirectShowVideoRendererControl();
+
+ QAbstractVideoSurface *surface() const;
+ void setSurface(QAbstractVideoSurface *surface);
+
+ IBaseFilter *filter();
+
+Q_SIGNALS:
+ void filterChanged();
+
+private:
+ DirectShowEventLoop *m_loop;
+ QAbstractVideoSurface *m_surface;
+ VideoSurfaceFilter *m_filter;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri
new file mode 100644
index 0000000..49ee9e5
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediaplayer.pri
@@ -0,0 +1,43 @@
+INCLUDEPATH += $$PWD
+
+DEFINES += QMEDIA_DIRECTSHOW_PLAYER
+
+HEADERS += \
+ $$PWD/directshowaudioendpointcontrol.h \
+ $$PWD/directshoweventloop.h \
+ $$PWD/directshowglobal.h \
+ $$PWD/directshowioreader.h \
+ $$PWD/directshowiosource.h \
+ $$PWD/directshowmediatype.h \
+ $$PWD/directshowmediatypelist.h \
+ $$PWD/directshowmetadatacontrol.h \
+ $$PWD/directshowpinenum.h \
+ $$PWD/directshowplayercontrol.h \
+ $$PWD/directshowplayerservice.h \
+ $$PWD/directshowsamplescheduler.h \
+ $$PWD/directshowvideooutputcontrol.h \
+ $$PWD/directshowvideorenderercontrol.h \
+ $$PWD/mediasamplevideobuffer.h \
+ $$PWD/videosurfacefilter.h \
+ $$PWD/vmr9videowindowcontrol.h
+
+SOURCES += \
+ $$PWD/directshowaudioendpointcontrol.cpp \
+ $$PWD/directshoweventloop.cpp \
+ $$PWD/directshowioreader.cpp \
+ $$PWD/directshowiosource.cpp \
+ $$PWD/directshowmediatype.cpp \
+ $$PWD/directshowmediatypelist.cpp \
+ $$PWD/directshowmetadatacontrol.cpp \
+ $$PWD/directshowpinenum.cpp \
+ $$PWD/directshowplayercontrol.cpp \
+ $$PWD/directshowplayerservice.cpp \
+ $$PWD/directshowsamplescheduler.cpp \
+ $$PWD/directshowvideooutputcontrol.cpp \
+ $$PWD/directshowvideorenderercontrol.cpp \
+ $$PWD/mediasamplevideobuffer.cpp \
+ $$PWD/videosurfacefilter.cpp \
+ $$PWD/vmr9videowindowcontrol.cpp
+
+LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp
new file mode 100644
index 0000000..7eff226
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mediasamplevideobuffer.h"
+
+
+QT_BEGIN_NAMESPACE
+
+MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine)
+ : QAbstractVideoBuffer(NoHandle)
+ , m_sample(sample)
+ , m_bytesPerLine(m_bytesPerLine)
+ , m_mapMode(NotMapped)
+{
+ m_sample->AddRef();
+}
+
+MediaSampleVideoBuffer::~MediaSampleVideoBuffer()
+{
+ m_sample->Release();
+}
+
+uchar *MediaSampleVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
+{
+ if (m_mapMode == NotMapped && mode != NotMapped) {
+ if (numBytes)
+ *numBytes = m_sample->GetActualDataLength();
+
+ if (bytesPerLine)
+ *bytesPerLine = m_bytesPerLine;
+
+ BYTE *bytes = 0;
+
+ if (m_sample->GetPointer(&bytes) == S_OK) {
+ m_mapMode = mode;
+
+ return reinterpret_cast<uchar *>(bytes);
+ }
+ }
+ return 0;
+}
+
+void MediaSampleVideoBuffer::unmap()
+{
+ m_mapMode = NotMapped;
+}
+
+QAbstractVideoBuffer::MapMode MediaSampleVideoBuffer::mapMode() const
+{
+ return m_mapMode;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h
new file mode 100644
index 0000000..06dc31c
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/mediasamplevideobuffer.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MEDIASAMPLEVIDEOBUFFER_H
+#define MEDIASAMPLEVIDEOBUFFER_H
+
+#include <QtMultimedia/qabstractvideobuffer.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class MediaSampleVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine);
+ ~MediaSampleVideoBuffer();
+
+ IMediaSample *sample() { return m_sample; }
+
+ uchar *map(MapMode mode, int *numBytes, int *bytesPerLine);
+ void unmap();
+
+ MapMode mapMode() const;
+
+private:
+ IMediaSample *m_sample;
+ int m_bytesPerLine;
+ MapMode m_mapMode;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp
new file mode 100644
index 0000000..a5565f1
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.cpp
@@ -0,0 +1,600 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "videosurfacefilter.h"
+
+#include "directshoweventloop.h"
+#include "directshowpinenum.h"
+#include "mediasamplevideobuffer.h"
+
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qthread.h>
+#include <QtMultimedia/qabstractvideosurface.h>
+
+#include <initguid.h>
+
+
+QT_BEGIN_NAMESPACE
+
+// { e23cad72-153d-406c-bf3f-4c4b523d96f2 }
+DEFINE_GUID(CLSID_VideoSurfaceFilter,
+0xe23cad72, 0x153d, 0x406c, 0xbf, 0x3f, 0x4c, 0x4b, 0x52, 0x3d, 0x96, 0xf2);
+
+VideoSurfaceFilter::VideoSurfaceFilter(
+ QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent)
+ : QObject(parent)
+ , m_ref(1)
+ , m_state(State_Stopped)
+ , m_surface(surface)
+ , m_loop(loop)
+ , m_graph(0)
+ , m_peerPin(0)
+ , m_bytesPerLine(0)
+ , m_startResult(S_OK)
+ , m_pinId(QString::fromLatin1("reference"))
+ , m_sampleScheduler(static_cast<IPin *>(this))
+{
+ connect(surface, SIGNAL(supportedFormatsChanged()), this, SLOT(supportedFormatsChanged()));
+ connect(&m_sampleScheduler, SIGNAL(sampleReady()), this, SLOT(sampleReady()));
+}
+
+VideoSurfaceFilter::~VideoSurfaceFilter()
+{
+ Q_ASSERT(m_ref == 1);
+}
+
+HRESULT VideoSurfaceFilter::QueryInterface(REFIID riid, void **ppvObject)
+{
+ if (!ppvObject) {
+ return E_POINTER;
+ } else if (riid == IID_IUnknown
+ || riid == IID_IPersist
+ || riid == IID_IMediaFilter
+ || riid == IID_IBaseFilter) {
+ *ppvObject = static_cast<IBaseFilter *>(this);
+ } else if (riid == IID_IAMFilterMiscFlags) {
+ *ppvObject = static_cast<IAMFilterMiscFlags *>(this);
+ } else if (riid == IID_IPin) {
+ *ppvObject = static_cast<IPin *>(this);
+ } else if (riid == IID_IMemInputPin) {
+ *ppvObject = static_cast<IMemInputPin *>(&m_sampleScheduler);
+ } else {
+ *ppvObject = 0;
+
+ return E_NOINTERFACE;
+ }
+
+ AddRef();
+
+ return S_OK;
+}
+
+ULONG VideoSurfaceFilter::AddRef()
+{
+ return InterlockedIncrement(&m_ref);
+}
+
+ULONG VideoSurfaceFilter::Release()
+{
+ ULONG ref = InterlockedDecrement(&m_ref);
+
+ Q_ASSERT(ref != 0);
+
+ return ref;
+}
+
+HRESULT VideoSurfaceFilter::GetClassID(CLSID *pClassID)
+{
+ *pClassID = CLSID_VideoSurfaceFilter;
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Run(REFERENCE_TIME tStart)
+{
+ m_state = State_Running;
+
+ m_sampleScheduler.run(tStart);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Pause()
+{
+ m_state = State_Paused;
+
+ m_sampleScheduler.pause();
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::Stop()
+{
+ m_state = State_Stopped;
+
+ m_sampleScheduler.stop();
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
+{
+ if (!pState)
+ return E_POINTER;
+
+ *pState = m_state;
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::SetSyncSource(IReferenceClock *pClock)
+{
+
+ m_sampleScheduler.setClock(pClock);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::GetSyncSource(IReferenceClock **ppClock)
+{
+ if (!ppClock) {
+ return E_POINTER;
+ } else {
+ *ppClock = m_sampleScheduler.clock();
+
+ if (*ppClock) {
+ (*ppClock)->AddRef();
+
+ return S_OK;
+ } else {
+ return S_FALSE;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::EnumPins(IEnumPins **ppEnum)
+{
+ if (ppEnum) {
+ *ppEnum = new DirectShowPinEnum(QList<IPin *>() << this);
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT VideoSurfaceFilter::FindPin(LPCWSTR pId, IPin **ppPin)
+{
+ if (!ppPin || !pId) {
+ return E_POINTER;
+ } else if (QString::fromWCharArray(pId) == m_pinId) {
+ AddRef();
+
+ *ppPin = this;
+
+ return S_OK;
+ } else {
+ return VFW_E_NOT_FOUND;
+ }
+}
+
+HRESULT VideoSurfaceFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
+{
+ m_graph = pGraph;
+ m_name = QString::fromWCharArray(pName);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::QueryFilterInfo(FILTER_INFO *pInfo)
+{
+ if (pInfo) {
+ QString name = m_name;
+
+ if (name.length() >= MAX_FILTER_NAME)
+ name.truncate(MAX_FILTER_NAME - 1);
+
+ int length = name.toWCharArray(pInfo->achName);
+ pInfo->achName[length] = '\0';
+
+ if (m_graph)
+ m_graph->AddRef();
+
+ pInfo->pGraph = m_graph;
+
+ return S_OK;
+ } else {
+ return E_POINTER;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryVendorInfo(LPWSTR *pVendorInfo)
+{
+ Q_UNUSED(pVendorInfo);
+
+ return E_NOTIMPL;
+}
+
+ULONG VideoSurfaceFilter::GetMiscFlags()
+{
+ return AM_FILTER_MISC_FLAGS_IS_RENDERER;
+}
+
+
+HRESULT VideoSurfaceFilter::Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt)
+{
+ // This is an input pin, you shouldn't be calling Connect on it.
+ return E_POINTER;
+}
+
+HRESULT VideoSurfaceFilter::ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt)
+{
+ if (!pConnector) {
+ return E_POINTER;
+ } else if (!pmt) {
+ return E_POINTER;
+ } else {
+ HRESULT hr;
+ QMutexLocker locker(&m_mutex);
+
+ if (m_peerPin) {
+ hr = VFW_E_ALREADY_CONNECTED;
+ } else if (pmt->majortype != MEDIATYPE_Video) {
+ hr = VFW_E_TYPE_NOT_ACCEPTED;
+ } else {
+ m_surfaceFormat = DirectShowMediaType::formatFromType(*pmt);
+ m_bytesPerLine = DirectShowMediaType::bytesPerLine(m_surfaceFormat);
+
+ if (thread() == QThread::currentThread()) {
+ hr = start();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(StartSurface)));
+
+ m_wait.wait(&m_mutex);
+
+ hr = m_startResult;
+ }
+ }
+ if (hr == S_OK) {
+ m_peerPin = pConnector;
+ m_peerPin->AddRef();
+
+ DirectShowMediaType::copy(&m_mediaType, *pmt);
+ }
+ return hr;
+ }
+}
+
+HRESULT VideoSurfaceFilter::start()
+{
+ if (!m_surface->start(m_surfaceFormat)) {
+ return VFW_E_TYPE_NOT_ACCEPTED;
+ } else {
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::Disconnect()
+{
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin)
+ return S_FALSE;
+
+ if (thread() == QThread::currentThread()) {
+ stop();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(StopSurface)));
+
+ m_wait.wait(&m_mutex);
+ }
+
+ m_mediaType.clear();
+
+ m_sampleScheduler.NotifyAllocator(0, FALSE);
+
+ m_peerPin->Release();
+ m_peerPin = 0;
+
+ return S_OK;
+}
+
+void VideoSurfaceFilter::stop()
+{
+ m_surface->stop();
+}
+
+HRESULT VideoSurfaceFilter::ConnectedTo(IPin **ppPin)
+{
+ if (!ppPin) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ m_peerPin->AddRef();
+
+ *ppPin = m_peerPin;
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::ConnectionMediaType(AM_MEDIA_TYPE *pmt)
+{
+ if (!pmt) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ if (!m_peerPin) {
+ return VFW_E_NOT_CONNECTED;
+ } else {
+ DirectShowMediaType::copy(pmt, m_mediaType);
+
+ return S_OK;
+ }
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryPinInfo(PIN_INFO *pInfo)
+{
+ if (!pInfo) {
+ return E_POINTER;
+ } else {
+ AddRef();
+
+ pInfo->pFilter = this;
+ pInfo->dir = PINDIR_INPUT;
+
+ const int bytes = qMin(MAX_FILTER_NAME, (m_pinId.length() + 1) * 2);
+
+ qMemCopy(pInfo->achName, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryId(LPWSTR *Id)
+{
+ if (!Id) {
+ return E_POINTER;
+ } else {
+ const int bytes = (m_pinId.length() + 1) * 2;
+
+ *Id = static_cast<LPWSTR>(::CoTaskMemAlloc(bytes));
+
+ qMemCopy(*Id, m_pinId.utf16(), bytes);
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryAccept(const AM_MEDIA_TYPE *pmt)
+{
+ return !m_surface->isFormatSupported(DirectShowMediaType::formatFromType(*pmt))
+ ? S_OK
+ : S_FALSE;
+}
+
+HRESULT VideoSurfaceFilter::EnumMediaTypes(IEnumMediaTypes **ppEnum)
+{
+ if (!ppEnum) {
+ return E_POINTER;
+ } else {
+ QMutexLocker locker(&m_mutex);
+
+ *ppEnum = createMediaTypeEnum();
+
+ return S_OK;
+ }
+}
+
+HRESULT VideoSurfaceFilter::QueryInternalConnections(IPin **apPin, ULONG *nPin)
+{
+ Q_UNUSED(apPin);
+ Q_UNUSED(nPin);
+
+ return E_NOTIMPL;
+}
+
+HRESULT VideoSurfaceFilter::EndOfStream()
+{
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::BeginFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_sampleScheduler.setFlushing(true);
+
+ if (thread() == QThread::currentThread()) {
+ flush();
+ } else {
+ m_loop->postEvent(this, new QEvent(QEvent::Type(FlushSurface)));
+
+ m_wait.wait(&m_mutex);
+ }
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::EndFlush()
+{
+ QMutexLocker locker(&m_mutex);
+
+ m_sampleScheduler.setFlushing(false);
+
+ return S_OK;
+}
+
+void VideoSurfaceFilter::flush()
+{
+ m_surface->present(QVideoFrame());
+
+ m_wait.wakeAll();
+}
+
+HRESULT VideoSurfaceFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
+{
+ Q_UNUSED(tStart);
+ Q_UNUSED(tStop);
+ Q_UNUSED(dRate);
+
+ return S_OK;
+}
+
+HRESULT VideoSurfaceFilter::QueryDirection(PIN_DIRECTION *pPinDir)
+{
+ if (!pPinDir) {
+ return E_POINTER;
+ } else {
+ *pPinDir = PINDIR_INPUT;
+
+ return S_OK;
+ }
+}
+
+int VideoSurfaceFilter::currentMediaTypeToken()
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::currentMediaTypeToken();
+}
+
+HRESULT VideoSurfaceFilter::nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::nextMediaType(token, index, count, types, fetchedCount);
+
+}
+
+HRESULT VideoSurfaceFilter::skipMediaType(int token, int *index, ULONG count)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::skipMediaType(token, index, count);
+}
+
+HRESULT VideoSurfaceFilter::cloneMediaType(int token, int index, IEnumMediaTypes **enumeration)
+{
+ QMutexLocker locker(&m_mutex);
+
+ return DirectShowMediaTypeList::cloneMediaType(token, index, enumeration);
+}
+
+void VideoSurfaceFilter::customEvent(QEvent *event)
+{
+ if (event->type() == StartSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ m_startResult = start();
+
+ m_wait.wakeAll();
+ } else if (event->type() == StopSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ stop();
+
+ m_wait.wakeAll();
+ } else if (event->type() == FlushSurface) {
+ QMutexLocker locker(&m_mutex);
+
+ flush();
+
+ m_wait.wakeAll();
+ } else {
+ QObject::customEvent(event);
+ }
+}
+
+void VideoSurfaceFilter::supportedFormatsChanged()
+{
+ QMutexLocker locker(&m_mutex);
+
+ QList<QVideoFrame::PixelFormat> formats = m_surface->supportedPixelFormats();
+
+ QVector<AM_MEDIA_TYPE> mediaTypes;
+ mediaTypes.reserve(formats.count());
+
+ AM_MEDIA_TYPE type;
+ type.majortype = MEDIATYPE_Video;
+ type.bFixedSizeSamples = TRUE;
+ type.bTemporalCompression = FALSE;
+ type.lSampleSize = 0;
+ type.formattype = GUID_NULL;
+ type.pUnk = 0;
+ type.cbFormat = 0;
+ type.pbFormat = 0;
+
+ foreach (QVideoFrame::PixelFormat format, formats) {
+ type.subtype = DirectShowMediaType::convertPixelFormat(format);
+
+ if (type.subtype != MEDIASUBTYPE_None)
+ mediaTypes.append(type);
+ }
+
+ setMediaTypes(mediaTypes);
+}
+
+void VideoSurfaceFilter::sampleReady()
+{
+ IMediaSample *sample = m_sampleScheduler.takeSample();
+
+ if (sample) {
+ m_surface->present(QVideoFrame(
+ new MediaSampleVideoBuffer(sample, m_bytesPerLine),
+ m_surfaceFormat.frameSize(),
+ m_surfaceFormat.pixelFormat()));
+
+ sample->Release();
+ }
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h
new file mode 100644
index 0000000..8f3a101
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/videosurfacefilter.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef VIDEOSURFACEFILTER_H
+#define VIDEOSURFACEFILTER_H
+
+#include "directshowmediatypelist.h"
+#include "directshowsamplescheduler.h"
+#include "directshowmediatype.h"
+
+#include <QtCore/qbasictimer.h>
+#include <QtCore/qcoreevent.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qsemaphore.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qwaitcondition.h>
+
+#include <dshow.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+
+class QAbstractVideoSurface;
+
+class DirectShowEventLoop;
+
+class VideoSurfaceFilter
+ : public QObject
+ , public DirectShowMediaTypeList
+ , public IBaseFilter
+ , public IAMFilterMiscFlags
+ , public IPin
+{
+ Q_OBJECT
+public:
+ VideoSurfaceFilter(
+ QAbstractVideoSurface *surface, DirectShowEventLoop *loop, QObject *parent = 0);
+ ~VideoSurfaceFilter();
+
+ // IUnknown
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ // IPersist
+ HRESULT STDMETHODCALLTYPE GetClassID(CLSID *pClassID);
+
+ // IMediaFilter
+ HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME tStart);
+ HRESULT STDMETHODCALLTYPE Pause();
+ HRESULT STDMETHODCALLTYPE Stop();
+
+ HRESULT STDMETHODCALLTYPE GetState(DWORD dwMilliSecsTimeout, FILTER_STATE *pState);
+
+ HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock *pClock);
+ HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock **ppClock);
+
+ // IBaseFilter
+ HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins **ppEnum);
+ HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR Id, IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
+
+ HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
+
+ // IAMFilterMiscFlags
+ ULONG STDMETHODCALLTYPE GetMiscFlags();
+
+ // IPin
+ HRESULT STDMETHODCALLTYPE Connect(IPin *pReceivePin, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE ReceiveConnection(IPin *pConnector, const AM_MEDIA_TYPE *pmt);
+ HRESULT STDMETHODCALLTYPE Disconnect();
+ HRESULT STDMETHODCALLTYPE ConnectedTo(IPin **ppPin);
+
+ HRESULT STDMETHODCALLTYPE ConnectionMediaType(AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE QueryPinInfo(PIN_INFO *pInfo);
+ HRESULT STDMETHODCALLTYPE QueryId(LPWSTR *Id);
+
+ HRESULT STDMETHODCALLTYPE QueryAccept(const AM_MEDIA_TYPE *pmt);
+
+ HRESULT STDMETHODCALLTYPE EnumMediaTypes(IEnumMediaTypes **ppEnum);
+
+ HRESULT STDMETHODCALLTYPE QueryInternalConnections(IPin **apPin, ULONG *nPin);
+
+ HRESULT STDMETHODCALLTYPE EndOfStream();
+
+ HRESULT STDMETHODCALLTYPE BeginFlush();
+ HRESULT STDMETHODCALLTYPE EndFlush();
+
+ HRESULT STDMETHODCALLTYPE NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate);
+
+ HRESULT STDMETHODCALLTYPE QueryDirection(PIN_DIRECTION *pPinDir);
+
+ int currentMediaTypeToken();
+ HRESULT nextMediaType(
+ int token, int *index, ULONG count, AM_MEDIA_TYPE **types, ULONG *fetchedCount);
+ HRESULT skipMediaType(int token, int *index, ULONG count);
+ HRESULT cloneMediaType(int token, int index, IEnumMediaTypes **enumeration);
+
+protected:
+ void customEvent(QEvent *event);
+
+private Q_SLOTS:
+ void supportedFormatsChanged();
+ void sampleReady();
+
+private:
+ HRESULT start();
+ void stop();
+ void flush();
+
+ enum
+ {
+ StartSurface = QEvent::User,
+ StopSurface,
+ FlushSurface
+ };
+
+ LONG m_ref;
+ FILTER_STATE m_state;
+ QAbstractVideoSurface *m_surface;
+ DirectShowEventLoop *m_loop;
+ IFilterGraph *m_graph;
+ IPin *m_peerPin;
+ int m_bytesPerLine;
+ HRESULT m_startResult;
+ QString m_name;
+ QString m_pinId;
+ DirectShowMediaType m_mediaType;
+ QVideoSurfaceFormat m_surfaceFormat;
+ QMutex m_mutex;
+ QWaitCondition m_wait;
+ DirectShowSampleScheduler m_sampleScheduler;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp
new file mode 100644
index 0000000..a564e14
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "vmr9videowindowcontrol.h"
+
+#include "directshowglobal.h"
+
+
+QT_BEGIN_NAMESPACE
+
+Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent)
+ : QVideoWindowControl(parent)
+ , m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9))
+ , m_windowId(0)
+ , m_dirtyValues(0)
+ , m_brightness(0)
+ , m_contrast(0)
+ , m_hue(0)
+ , m_saturation(0)
+ , m_fullScreen(false)
+{
+ if (IVMRFilterConfig9 *config = com_cast<IVMRFilterConfig9>(m_filter)) {
+ config->SetRenderingMode(VMR9Mode_Windowless);
+ config->SetNumberOfStreams(1);
+ config->Release();
+ }
+}
+
+Vmr9VideoWindowControl::~Vmr9VideoWindowControl()
+{
+ if (m_filter)
+ m_filter->Release();
+}
+
+
+WId Vmr9VideoWindowControl::winId() const
+{
+ return m_windowId;
+
+}
+
+void Vmr9VideoWindowControl::setWinId(WId id)
+{
+ m_windowId = id;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ control->SetVideoClippingWindow(m_windowId);
+ control->Release();
+ }
+}
+
+QRect Vmr9VideoWindowControl::displayRect() const
+{
+ QRect rect;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ RECT sourceRect;
+ RECT displayRect;
+
+ if (control->GetVideoPosition(&sourceRect, &displayRect) == S_OK) {
+ rect = QRect(
+ displayRect.left,
+ displayRect.bottom,
+ displayRect.right - displayRect.left,
+ displayRect.bottom - displayRect.top);
+ }
+ control->Release();
+ }
+ return rect;
+}
+
+void Vmr9VideoWindowControl::setDisplayRect(const QRect &rect)
+{
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ RECT sourceRect = { 0, 0, 0, 0 };
+ RECT displayRect = { rect.left(), rect.top(), rect.right(), rect.bottom() };
+
+ control->GetNativeVideoSize(&sourceRect.right, &sourceRect.bottom, 0, 0);
+ control->SetVideoPosition(&sourceRect, &displayRect);
+ control->Release();
+ }
+}
+
+bool Vmr9VideoWindowControl::isFullScreen() const
+{
+ return m_fullScreen;
+}
+
+void Vmr9VideoWindowControl::setFullScreen(bool fullScreen)
+{
+ emit fullScreenChanged(m_fullScreen = fullScreen);
+}
+
+void Vmr9VideoWindowControl::repaint()
+{
+
+ if (QWidget *widget = QWidget::find(m_windowId)) {
+ HDC dc = widget->getDC();
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ control->RepaintVideo(m_windowId, dc);
+ control->Release();
+ }
+ widget->releaseDC(dc);
+ }
+}
+
+QSize Vmr9VideoWindowControl::nativeSize() const
+{
+ QSize size;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ LONG width;
+ LONG height;
+
+ if (control->GetNativeVideoSize(&width, &height, 0, 0) == S_OK)
+ size = QSize(width, height);
+ control->Release();
+ }
+ return size;
+}
+
+QVideoWidget::AspectRatioMode Vmr9VideoWindowControl::aspectRatioMode() const
+{
+ QVideoWidget::AspectRatioMode mode = QVideoWidget::KeepAspectRatio;
+
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ DWORD arMode;
+
+ if (control->GetAspectRatioMode(&arMode) == S_OK && arMode == VMR9ARMode_None)
+ mode = QVideoWidget::IgnoreAspectRatio;
+ control->Release();
+ }
+ return mode;
+}
+
+void Vmr9VideoWindowControl::setAspectRatioMode(QVideoWidget::AspectRatioMode mode)
+{
+ if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(m_filter)) {
+ switch (mode) {
+ case QVideoWidget::IgnoreAspectRatio:
+ control->SetAspectRatioMode(VMR9ARMode_None);
+ break;
+ case QVideoWidget::KeepAspectRatio:
+ control->SetAspectRatioMode(VMR9ARMode_LetterBox);
+ break;
+ default:
+ break;
+ }
+ control->Release();
+ }
+}
+
+int Vmr9VideoWindowControl::brightness() const
+{
+ return m_brightness;
+}
+
+void Vmr9VideoWindowControl::setBrightness(int brightness)
+{
+ m_brightness = brightness;
+
+ m_dirtyValues |= ProcAmpControl9_Brightness;
+
+ setProcAmpValues();
+
+ emit brightnessChanged(brightness);
+}
+
+int Vmr9VideoWindowControl::contrast() const
+{
+ return m_contrast;
+}
+
+void Vmr9VideoWindowControl::setContrast(int contrast)
+{
+ m_contrast = contrast;
+
+ m_dirtyValues |= ProcAmpControl9_Contrast;
+
+ setProcAmpValues();
+
+ emit contrastChanged(contrast);
+}
+
+int Vmr9VideoWindowControl::hue() const
+{
+ return m_hue;
+}
+
+void Vmr9VideoWindowControl::setHue(int hue)
+{
+ m_hue = hue;
+
+ m_dirtyValues |= ProcAmpControl9_Hue;
+
+ setProcAmpValues();
+
+ emit hueChanged(hue);
+}
+
+int Vmr9VideoWindowControl::saturation() const
+{
+ return m_saturation;
+}
+
+void Vmr9VideoWindowControl::setSaturation(int saturation)
+{
+ m_saturation = saturation;
+
+ m_dirtyValues |= ProcAmpControl9_Saturation;
+
+ setProcAmpValues();
+
+ emit saturationChanged(saturation);
+}
+
+void Vmr9VideoWindowControl::setProcAmpValues()
+{
+ if (IVMRMixerControl9 *control = com_cast<IVMRMixerControl9>(m_filter)) {
+ VMR9ProcAmpControl procAmp;
+ procAmp.dwSize = sizeof(VMR9ProcAmpControl);
+ procAmp.dwFlags = m_dirtyValues;
+
+ if (m_dirtyValues & ProcAmpControl9_Brightness) {
+ procAmp.Brightness = scaleProcAmpValue(
+ control, ProcAmpControl9_Brightness, m_brightness);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Contrast) {
+ procAmp.Contrast = scaleProcAmpValue(
+ control, ProcAmpControl9_Contrast, m_contrast);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Hue) {
+ procAmp.Hue = scaleProcAmpValue(
+ control, ProcAmpControl9_Hue, m_hue);
+ }
+ if (m_dirtyValues & ProcAmpControl9_Saturation) {
+ procAmp.Saturation = scaleProcAmpValue(
+ control, ProcAmpControl9_Saturation, m_saturation);
+ }
+
+ if (SUCCEEDED(control->SetProcAmpControl(0, &procAmp))) {
+ m_dirtyValues = 0;
+ }
+
+ control->Release();
+ }
+}
+
+float Vmr9VideoWindowControl::scaleProcAmpValue(
+ IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const
+{
+ float scaledValue = 0.0;
+
+ VMR9ProcAmpControlRange range;
+ range.dwSize = sizeof(VMR9ProcAmpControlRange);
+ range.dwProperty = property;
+
+ if (SUCCEEDED(control->GetProcAmpControlRange(0, &range))) {
+ scaledValue = range.DefaultValue;
+ if (value > 0)
+ scaledValue += float(value) * (range.MaxValue - range.DefaultValue) / 100;
+ else if (value < 0)
+ scaledValue -= float(value) * (range.MinValue - range.DefaultValue) / 100;
+ }
+
+ return scaledValue;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h
new file mode 100644
index 0000000..a0aca95
--- /dev/null
+++ b/src/plugins/mediaservices/directshow/mediaplayer/vmr9videowindowcontrol.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VMR9VIDEOWINDOWCONTROL_H
+#define VMR9VIDEOWINDOWCONTROL_H
+
+#include <QtMultimedia/qvideowindowcontrol.h>
+
+#include <dshow.h>
+#include <d3d9.h>
+#include <vmr9.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class Vmr9VideoWindowControl : public QVideoWindowControl
+{
+ Q_OBJECT
+public:
+ Vmr9VideoWindowControl(QObject *parent = 0);
+ ~Vmr9VideoWindowControl();
+
+ IBaseFilter *filter() const { return m_filter; }
+
+ WId winId() const;
+ void setWinId(WId id);
+
+ QRect displayRect() const;
+ void setDisplayRect(const QRect &rect);
+
+ bool isFullScreen() const;
+ void setFullScreen(bool fullScreen);
+
+ void repaint();
+
+ QSize nativeSize() const;
+
+ QVideoWidget::AspectRatioMode aspectRatioMode() const;
+ void setAspectRatioMode(QVideoWidget::AspectRatioMode mode);
+
+ int brightness() const;
+ void setBrightness(int brightness);
+
+ int contrast() const;
+ void setContrast(int contrast);
+
+ int hue() const;
+ void setHue(int hue);
+
+ int saturation() const;
+ void setSaturation(int saturation);
+
+private:
+ void setProcAmpValues();
+ float scaleProcAmpValue(
+ IVMRMixerControl9 *control, VMR9ProcAmpControlFlags property, int value) const;
+
+ IBaseFilter *m_filter;
+ WId m_windowId;
+ DWORD m_dirtyValues;
+ int m_brightness;
+ int m_contrast;
+ int m_hue;
+ int m_saturation;
+ bool m_fullScreen;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/plugins/mediaservices/mediaservices.pro b/src/plugins/mediaservices/mediaservices.pro
index 879d914..e48156b 100644
--- a/src/plugins/mediaservices/mediaservices.pro
+++ b/src/plugins/mediaservices/mediaservices.pro
@@ -1,5 +1,7 @@
TEMPLATE = subdirs
+win32:!wince:SUBDIRS += directshow
+
mac:SUBDIRS += qt7
unix:!mac:!symbian {