Initial copy of QtMultimediaKit.
Comes from original repo, with SHA1: 2c82d5611655e5967f5c5095af50c0991c4378b2
This commit is contained in:
161
src/plugins/directshow/player/directshowaudioendpointcontrol.cpp
Normal file
161
src/plugins/directshow/player/directshowaudioendpointcontrol.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowaudioendpointcontrol.h"
|
||||
|
||||
#include "directshowglobal.h"
|
||||
#include "directshowplayerservice.h"
|
||||
|
||||
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, IID_ICreateDevEnum);
|
||||
|
||||
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
|
||||
{
|
||||
#ifdef __IPropertyBag_INTERFACE_DEFINED__
|
||||
QString description;
|
||||
|
||||
if (IMoniker *moniker = m_devices.value(name, 0)) {
|
||||
IPropertyBag *propertyBag = 0;
|
||||
if (SUCCEEDED(moniker->BindToStorage(
|
||||
0, 0, IID_IPropertyBag, reinterpret_cast<void **>(&propertyBag)))) {
|
||||
VARIANT name;
|
||||
VariantInit(&name);
|
||||
if (SUCCEEDED(propertyBag->Read(L"FriendlyName", &name, 0)))
|
||||
description = QString::fromWCharArray(name.bstrVal);
|
||||
VariantClear(&name);
|
||||
propertyBag->Release();
|
||||
}
|
||||
}
|
||||
|
||||
return description;
|
||||
#else
|
||||
return name.section(QLatin1Char('\\'), -1);
|
||||
#endif
|
||||
}
|
||||
|
||||
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,
|
||||
IID_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(deviceId, moniker);
|
||||
|
||||
if (m_defaultEndpoint.isEmpty()
|
||||
|| deviceId.endsWith(QLatin1String("Default DirectSound Device"))) {
|
||||
m_defaultEndpoint = deviceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
monikers->Release();
|
||||
}
|
||||
oleMalloc->Release();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWAUDIOENDPOINTCONTROL_H
|
||||
#define DIRECTSHOWAUDIOENDPOINTCONTROL_H
|
||||
|
||||
#include "qaudioendpointselector.h"
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
class DirectShowPlayerService;
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
150
src/plugins/directshow/player/directshoweventloop.cpp
Normal file
150
src/plugins/directshow/player/directshoweventloop.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <directshoweventloop.h>
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qcoreevent.h>
|
||||
|
||||
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)
|
||||
: QObject(parent)
|
||||
, m_postsHead(0)
|
||||
, m_postsTail(0)
|
||||
, m_eventHandle(::CreateEvent(0, 0, 0, 0))
|
||||
, m_waitHandle(::CreateEvent(0, 0, 0, 0))
|
||||
{
|
||||
}
|
||||
|
||||
DirectShowEventLoop::~DirectShowEventLoop()
|
||||
{
|
||||
::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;
|
||||
|
||||
QCoreApplication::postEvent(this, new QEvent(QEvent::User));
|
||||
::SetEvent(m_eventHandle);
|
||||
}
|
||||
|
||||
void DirectShowEventLoop::customEvent(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::User) {
|
||||
processEvents();
|
||||
} else {
|
||||
QObject::customEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DirectShowEventLoop::processEvents()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
::ResetEvent(m_eventHandle);
|
||||
|
||||
while(m_postsHead) {
|
||||
DirectShowPostedEvent *post = m_postsHead;
|
||||
m_postsHead = m_postsHead->next;
|
||||
|
||||
if (!m_postsHead)
|
||||
m_postsTail = 0;
|
||||
|
||||
locker.unlock();
|
||||
QCoreApplication::sendEvent(post->receiver, post->event);
|
||||
delete post;
|
||||
locker.relock();
|
||||
}
|
||||
}
|
||||
78
src/plugins/directshow/player/directshoweventloop.h
Normal file
78
src/plugins/directshow/player/directshoweventloop.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWEVENTLOOP_H
|
||||
#define DIRECTSHOWEVENTLOOP_H
|
||||
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qwaitcondition.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class DirectShowPostedEvent;
|
||||
|
||||
class DirectShowEventLoop : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DirectShowEventLoop(QObject *parent = 0);
|
||||
~DirectShowEventLoop();
|
||||
|
||||
void wait(QMutex *mutex);
|
||||
void wake();
|
||||
|
||||
void postEvent(QObject *object, QEvent *event);
|
||||
|
||||
protected:
|
||||
void customEvent(QEvent *event);
|
||||
|
||||
private:
|
||||
void processEvents();
|
||||
|
||||
DirectShowPostedEvent *m_postsHead;
|
||||
DirectShowPostedEvent *m_postsTail;
|
||||
HANDLE m_eventHandle;
|
||||
HANDLE m_waitHandle;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
139
src/plugins/directshow/player/directshowglobal.h
Normal file
139
src/plugins/directshow/player/directshowglobal.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWGLOBAL_H
|
||||
#define DIRECTSHOWGLOBAL_H
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
template <typename T> T *com_cast(IUnknown *unknown, const IID &iid)
|
||||
{
|
||||
T *iface = 0;
|
||||
return unknown && unknown->QueryInterface(iid, reinterpret_cast<void **>(&iface)) == S_OK
|
||||
? iface
|
||||
: 0;
|
||||
}
|
||||
|
||||
template <typename T> T *com_new(const IID &clsid, const IID &iid)
|
||||
{
|
||||
T *object = 0;
|
||||
return CoCreateInstance(
|
||||
clsid,
|
||||
NULL,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
iid,
|
||||
reinterpret_cast<void **>(&object)) == S_OK
|
||||
? object
|
||||
: 0;
|
||||
}
|
||||
|
||||
#ifndef __IFilterGraph2_INTERFACE_DEFINED__
|
||||
#define __IFilterGraph2_INTERFACE_DEFINED__
|
||||
#define INTERFACE IFilterGraph2
|
||||
DECLARE_INTERFACE_(IFilterGraph2 ,IGraphBuilder)
|
||||
{
|
||||
STDMETHOD(AddSourceFilterForMoniker)(THIS_ IMoniker *, IBindCtx *, LPCWSTR,IBaseFilter **) PURE;
|
||||
STDMETHOD(ReconnectEx)(THIS_ IPin *, const AM_MEDIA_TYPE *) PURE;
|
||||
STDMETHOD(RenderEx)(IPin *, DWORD, DWORD *) PURE;
|
||||
};
|
||||
#undef INTERFACE
|
||||
#endif
|
||||
|
||||
#ifndef __IAMFilterMiscFlags_INTERFACE_DEFINED__
|
||||
#define __IAMFilterMiscFlags_INTERFACE_DEFINED__
|
||||
#define INTERFACE IAMFilterMiscFlags
|
||||
DECLARE_INTERFACE_(IAMFilterMiscFlags ,IUnknown)
|
||||
{
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
|
||||
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,Release)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,GetMiscFlags)(THIS) PURE;
|
||||
};
|
||||
#undef INTERFACE
|
||||
#endif
|
||||
|
||||
#ifndef __IFileSourceFilter_INTERFACE_DEFINED__
|
||||
#define __IFileSourceFilter_INTERFACE_DEFINED__
|
||||
#define INTERFACE IFileSourceFilter
|
||||
DECLARE_INTERFACE_(IFileSourceFilter ,IUnknown)
|
||||
{
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
|
||||
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,Release)(THIS) PURE;
|
||||
STDMETHOD(Load)(THIS_ LPCOLESTR, const AM_MEDIA_TYPE *) PURE;
|
||||
STDMETHOD(GetCurFile)(THIS_ LPOLESTR *ppszFileName, AM_MEDIA_TYPE *) PURE;
|
||||
};
|
||||
#undef INTERFACE
|
||||
#endif
|
||||
|
||||
#ifndef __IAMOpenProgress_INTERFACE_DEFINED__
|
||||
#define __IAMOpenProgress_INTERFACE_DEFINED__
|
||||
#define INTERFACE IAMOpenProgress
|
||||
DECLARE_INTERFACE_(IAMOpenProgress ,IUnknown)
|
||||
{
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
|
||||
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,Release)(THIS) PURE;
|
||||
STDMETHOD(QueryProgress)(THIS_ LONGLONG *, LONGLONG *) PURE;
|
||||
STDMETHOD(AbortOperation)(THIS) PURE;
|
||||
};
|
||||
#undef INTERFACE
|
||||
#endif
|
||||
|
||||
#ifndef __IFilterChain_INTERFACE_DEFINED__
|
||||
#define __IFilterChain_INTERFACE_DEFINED__
|
||||
#define INTERFACE IFilterChain
|
||||
DECLARE_INTERFACE_(IFilterChain ,IUnknown)
|
||||
{
|
||||
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
|
||||
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
|
||||
STDMETHOD_(ULONG,Release)(THIS) PURE;
|
||||
STDMETHOD(StartChain)(IBaseFilter *, IBaseFilter *) PURE;
|
||||
STDMETHOD(PauseChain)(IBaseFilter *, IBaseFilter *) PURE;
|
||||
STDMETHOD(StopChain)(IBaseFilter *, IBaseFilter *) PURE;
|
||||
STDMETHOD(RemoveChain)(IBaseFilter *, IBaseFilter *) PURE;
|
||||
};
|
||||
#undef INTERFACE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
496
src/plugins/directshow/player/directshowioreader.cpp
Normal file
496
src/plugins/directshow/player/directshowioreader.cpp
Normal file
@@ -0,0 +1,496 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "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>
|
||||
|
||||
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, IID_IMemAllocator);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
120
src/plugins/directshow/player/directshowioreader.h
Normal file
120
src/plugins/directshow/player/directshowioreader.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWIOREADER_H
|
||||
#define DIRECTSHOWIOREADER_H
|
||||
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qwaitcondition.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QIODevice;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
639
src/plugins/directshow/player/directshowiosource.cpp
Normal file
639
src/plugins/directshow/player/directshowiosource.cpp
Normal file
@@ -0,0 +1,639 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowiosource.h"
|
||||
|
||||
#include "directshowglobal.h"
|
||||
#include "directshowmediatype.h"
|
||||
#include "directshowpinenum.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qurl.h>
|
||||
|
||||
static const GUID directshow_subtypes[] =
|
||||
{
|
||||
MEDIASUBTYPE_Avi,
|
||||
MEDIASUBTYPE_WAVE,
|
||||
MEDIASUBTYPE_NULL
|
||||
};
|
||||
|
||||
DirectShowIOSource::DirectShowIOSource(DirectShowEventLoop *loop)
|
||||
: m_ref(1)
|
||||
, m_state(State_Stopped)
|
||||
, m_reader(0)
|
||||
, m_loop(loop)
|
||||
, m_graph(0)
|
||||
, m_clock(0)
|
||||
, m_allocator(0)
|
||||
, m_peerPin(0)
|
||||
, m_pinId(QLatin1String("Data"))
|
||||
{
|
||||
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);
|
||||
|
||||
delete m_reader;
|
||||
}
|
||||
|
||||
void DirectShowIOSource::setDevice(QIODevice *device)
|
||||
{
|
||||
Q_ASSERT(!m_reader);
|
||||
|
||||
m_reader = new DirectShowIOReader(device, this, m_loop);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// 2dd74950-a890-11d1-abe8-00a0c905f375
|
||||
static const GUID iid_IAmFilterMiscFlags = {
|
||||
0x2dd74950, 0xa890, 0x11d1, {0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75}};
|
||||
|
||||
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, IID_IMemInputPin)) {
|
||||
if ((m_allocator = com_new<IMemAllocator>(CLSID_MemoryAllocator, IID_IMemAllocator))) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
DirectShowRcSource::DirectShowRcSource(DirectShowEventLoop *loop)
|
||||
: DirectShowIOSource(loop)
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectShowRcSource::open(const QUrl &url)
|
||||
{
|
||||
m_file.moveToThread(QCoreApplication::instance()->thread());
|
||||
|
||||
m_file.setFileName(QLatin1Char(':') + url.path());
|
||||
|
||||
qDebug("qrc file %s", qPrintable(m_file.fileName()));
|
||||
|
||||
if (m_file.open(QIODevice::ReadOnly)) {
|
||||
qDebug("Size %d", m_file.size());
|
||||
qDebug("Sequential %d", int(m_file.isSequential()));
|
||||
|
||||
setDevice(&m_file);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
149
src/plugins/directshow/player/directshowiosource.h
Normal file
149
src/plugins/directshow/player/directshowiosource.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWIOSOURCE_H
|
||||
#define DIRECTSHOWIOSOURCE_H
|
||||
|
||||
#include "directshowglobal.h"
|
||||
#include "directshowioreader.h"
|
||||
#include "directshowmediatype.h"
|
||||
#include "directshowmediatypelist.h"
|
||||
|
||||
#include <QtCore/qfile.h>
|
||||
|
||||
class DirectShowIOSource
|
||||
: public DirectShowMediaTypeList
|
||||
, public IBaseFilter
|
||||
, public IAMFilterMiscFlags
|
||||
, public IPin
|
||||
{
|
||||
public:
|
||||
DirectShowIOSource(DirectShowEventLoop *loop);
|
||||
~DirectShowIOSource();
|
||||
|
||||
void setDevice(QIODevice *device);
|
||||
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;
|
||||
DirectShowIOReader *m_reader;
|
||||
DirectShowEventLoop *m_loop;
|
||||
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;
|
||||
};
|
||||
|
||||
class DirectShowRcSource : public DirectShowIOSource
|
||||
{
|
||||
public:
|
||||
DirectShowRcSource(DirectShowEventLoop *loop);
|
||||
|
||||
bool open(const QUrl &url);
|
||||
|
||||
private:
|
||||
QFile m_file;
|
||||
};
|
||||
|
||||
#endif
|
||||
184
src/plugins/directshow/player/directshowmediatype.cpp
Normal file
184
src/plugins/directshow/player/directshowmediatype.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowmediatype.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct TypeLookup
|
||||
{
|
||||
QVideoFrame::PixelFormat pixelFormat;
|
||||
GUID mediaType;
|
||||
};
|
||||
|
||||
static const TypeLookup qt_typeLookup[] =
|
||||
{
|
||||
{ QVideoFrame::Format_RGB32, /*MEDIASUBTYPE_RGB32*/ {0xe436eb7e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} },
|
||||
{ QVideoFrame::Format_BGR24, /*MEDIASUBTYPE_RGB24*/ {0xe436eb7d, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} },
|
||||
{ QVideoFrame::Format_RGB565, /*MEDIASUBTYPE_RGB565*/ {0xe436eb7b, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} },
|
||||
{ QVideoFrame::Format_RGB555, /*MEDIASUBTYPE_RGB555*/ {0xe436eb7c, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}} },
|
||||
{ QVideoFrame::Format_AYUV444, /*MEDIASUBTYPE_AYUV*/ {0x56555941, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_YUYV, /*MEDIASUBTYPE_YUY2*/ {0x32595559, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_UYVY, /*MEDIASUBTYPE_UYVY*/ {0x59565955, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_IMC1, /*MEDIASUBTYPE_IMC1*/ {0x31434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_IMC2, /*MEDIASUBTYPE_IMC2*/ {0x32434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_IMC3, /*MEDIASUBTYPE_IMC3*/ {0x33434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_IMC4, /*MEDIASUBTYPE_IMC4*/ {0x34434D49, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_YV12, /*MEDIASUBTYPE_YV12*/ {0x32315659, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_NV12, /*MEDIASUBTYPE_NV12*/ {0x3231564E, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} },
|
||||
{ QVideoFrame::Format_YUV420P, /*MEDIASUBTYPE_IYUV*/ {0x56555949, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} }
|
||||
};
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// MEDIASUBTYPE_None;
|
||||
static const GUID none = {
|
||||
0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} };
|
||||
|
||||
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 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()) {
|
||||
// 32 bpp packed formats.
|
||||
case QVideoFrame::Format_RGB32:
|
||||
case QVideoFrame::Format_AYUV444:
|
||||
return format.frameWidth() * 4;
|
||||
// 24 bpp packed formats.
|
||||
case QVideoFrame::Format_RGB24:
|
||||
return format.frameWidth() * 3 + 3 - format.frameWidth() % 4;
|
||||
// 16 bpp packed formats.
|
||||
case QVideoFrame::Format_RGB565:
|
||||
case QVideoFrame::Format_RGB555:
|
||||
case QVideoFrame::Format_YUYV:
|
||||
case QVideoFrame::Format_UYVY:
|
||||
return format.frameWidth() * 2 + 3 - format.frameWidth() % 4;
|
||||
// Planar formats.
|
||||
case QVideoFrame::Format_IMC1:
|
||||
case QVideoFrame::Format_IMC2:
|
||||
case QVideoFrame::Format_IMC3:
|
||||
case QVideoFrame::Format_IMC4:
|
||||
case QVideoFrame::Format_YV12:
|
||||
case QVideoFrame::Format_NV12:
|
||||
case QVideoFrame::Format_YUV420P:
|
||||
return format.frameWidth() + 3 - format.frameWidth() % 4;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
74
src/plugins/directshow/player/directshowmediatype.h
Normal file
74
src/plugins/directshow/player/directshowmediatype.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWMEDIATYPE_H
|
||||
#define DIRECTSHOWMEDIATYPE_H
|
||||
|
||||
#include <qvideosurfaceformat.h>
|
||||
|
||||
#include <dshow.h>
|
||||
#include <dvdmedia.h>
|
||||
|
||||
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) {
|
||||
freeData(this); copy(this, type); return *this; }
|
||||
DirectShowMediaType &operator =(const DirectShowMediaType &other) {
|
||||
freeData(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);
|
||||
};
|
||||
|
||||
#endif
|
||||
226
src/plugins/directshow/player/directshowmediatypelist.cpp
Normal file
226
src/plugins/directshow/player/directshowmediatypelist.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowmediatypelist.h"
|
||||
|
||||
#include "directshowmediatype.h"
|
||||
#include "videosurfacefilter.h"
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
69
src/plugins/directshow/player/directshowmediatypelist.h
Normal file
69
src/plugins/directshow/player/directshowmediatypelist.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWMEDIATYPELIST_H
|
||||
#define DIRECTSHOWMEDIATYPELIST_H
|
||||
|
||||
#include <QtCore/qvector.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
352
src/plugins/directshow/player/directshowmetadatacontrol.cpp
Normal file
352
src/plugins/directshow/player/directshowmetadatacontrol.cpp
Normal file
@@ -0,0 +1,352 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <dshow.h>
|
||||
#include <initguid.h>
|
||||
#include <qnetwork.h>
|
||||
|
||||
#include "directshowmetadatacontrol.h"
|
||||
|
||||
#include "directshowplayerservice.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
|
||||
#ifndef QT_NO_WMSDK
|
||||
namespace
|
||||
{
|
||||
struct QWMMetaDataKeyLookup
|
||||
{
|
||||
QtMultimediaKit::MetaData key;
|
||||
const wchar_t *token;
|
||||
};
|
||||
}
|
||||
|
||||
static const QWMMetaDataKeyLookup qt_wmMetaDataKeys[] =
|
||||
{
|
||||
{ QtMultimediaKit::Title, L"Title" },
|
||||
{ QtMultimediaKit::SubTitle, L"WM/SubTitle" },
|
||||
{ QtMultimediaKit::Author, L"Author" },
|
||||
{ QtMultimediaKit::Comment, L"Comment" },
|
||||
{ QtMultimediaKit::Description, L"Description" },
|
||||
{ QtMultimediaKit::Category, L"WM/Category" },
|
||||
{ QtMultimediaKit::Genre, L"WM/Genre" },
|
||||
//{ QtMultimediaKit::Date, 0 },
|
||||
{ QtMultimediaKit::Year, L"WM/Year" },
|
||||
{ QtMultimediaKit::UserRating, L"UserRating" },
|
||||
//{ QtMultimediaKit::MetaDatawords, 0 },
|
||||
{ QtMultimediaKit::Language, L"Language" },
|
||||
{ QtMultimediaKit::Publisher, L"WM/Publisher" },
|
||||
{ QtMultimediaKit::Copyright, L"Copyright" },
|
||||
{ QtMultimediaKit::ParentalRating, L"ParentalRating" },
|
||||
{ QtMultimediaKit::RatingOrganisation, L"RatingOrganisation" },
|
||||
|
||||
// Media
|
||||
{ QtMultimediaKit::Size, L"FileSize" },
|
||||
{ QtMultimediaKit::MediaType, L"MediaType" },
|
||||
{ QtMultimediaKit::Duration, L"Duration" },
|
||||
|
||||
// Audio
|
||||
{ QtMultimediaKit::AudioBitRate, L"AudioBitRate" },
|
||||
{ QtMultimediaKit::AudioCodec, L"AudioCodec" },
|
||||
{ QtMultimediaKit::ChannelCount, L"ChannelCount" },
|
||||
{ QtMultimediaKit::SampleRate, L"Frequency" },
|
||||
|
||||
// Music
|
||||
{ QtMultimediaKit::AlbumTitle, L"WM/AlbumTitle" },
|
||||
{ QtMultimediaKit::AlbumArtist, L"WM/AlbumArtist" },
|
||||
{ QtMultimediaKit::ContributingArtist, L"Author" },
|
||||
{ QtMultimediaKit::Composer, L"WM/Composer" },
|
||||
{ QtMultimediaKit::Conductor, L"WM/Conductor" },
|
||||
{ QtMultimediaKit::Lyrics, L"WM/Lyrics" },
|
||||
{ QtMultimediaKit::Mood, L"WM/Mood" },
|
||||
{ QtMultimediaKit::TrackNumber, L"WM/TrackNumber" },
|
||||
//{ QtMultimediaKit::TrackCount, 0 },
|
||||
//{ QtMultimediaKit::CoverArtUriSmall, 0 },
|
||||
//{ QtMultimediaKit::CoverArtUriLarge, 0 },
|
||||
|
||||
// Image/Video
|
||||
//{ QtMultimediaKit::Resolution, 0 },
|
||||
//{ QtMultimediaKit::PixelAspectRatio, 0 },
|
||||
|
||||
// Video
|
||||
//{ QtMultimediaKit::FrameRate, 0 },
|
||||
{ QtMultimediaKit::VideoBitRate, L"VideoBitRate" },
|
||||
{ QtMultimediaKit::VideoCodec, L"VideoCodec" },
|
||||
|
||||
//{ QtMultimediaKit::PosterUri, 0 },
|
||||
|
||||
// Movie
|
||||
{ QtMultimediaKit::ChapterNumber, L"ChapterNumber" },
|
||||
{ QtMultimediaKit::Director, L"WM/Director" },
|
||||
{ QtMultimediaKit::LeadPerformer, L"LeadPerformer" },
|
||||
{ QtMultimediaKit::Writer, L"WM/Writer" },
|
||||
|
||||
// Photos
|
||||
{ QtMultimediaKit::CameraManufacturer, L"CameraManufacturer" },
|
||||
{ QtMultimediaKit::CameraModel, L"CameraModel" },
|
||||
{ QtMultimediaKit::Event, L"Event" },
|
||||
{ QtMultimediaKit::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();
|
||||
}
|
||||
#endif
|
||||
|
||||
DirectShowMetaDataControl::DirectShowMetaDataControl(QObject *parent)
|
||||
: QMetaDataReaderControl(parent)
|
||||
, m_content(0)
|
||||
#ifndef QT_NO_WMSDK
|
||||
, m_headerInfo(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
DirectShowMetaDataControl::~DirectShowMetaDataControl()
|
||||
{
|
||||
}
|
||||
|
||||
bool DirectShowMetaDataControl::isMetaDataAvailable() const
|
||||
{
|
||||
#ifndef QT_NO_WMSDK
|
||||
return m_content || m_headerInfo;
|
||||
#else
|
||||
return m_content;
|
||||
#endif
|
||||
}
|
||||
|
||||
QVariant DirectShowMetaDataControl::metaData(QtMultimediaKit::MetaData key) const
|
||||
{
|
||||
QVariant value;
|
||||
|
||||
#ifndef QT_NO_WMSDK
|
||||
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) {
|
||||
#else
|
||||
if (m_content) {
|
||||
#endif
|
||||
BSTR string = 0;
|
||||
|
||||
switch (key) {
|
||||
case QtMultimediaKit::Author:
|
||||
m_content->get_AuthorName(&string);
|
||||
break;
|
||||
case QtMultimediaKit::Title:
|
||||
m_content->get_Title(&string);
|
||||
break;
|
||||
case QtMultimediaKit::ParentalRating:
|
||||
m_content->get_Rating(&string);
|
||||
break;
|
||||
case QtMultimediaKit::Description:
|
||||
m_content->get_Description(&string);
|
||||
break;
|
||||
case QtMultimediaKit::Copyright:
|
||||
m_content->get_Copyright(&string);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (string) {
|
||||
value = QString::fromUtf16(reinterpret_cast<ushort *>(string), ::SysStringLen(string));
|
||||
|
||||
::SysFreeString(string);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
QList<QtMultimediaKit::MetaData> DirectShowMetaDataControl::availableMetaData() const
|
||||
{
|
||||
return QList<QtMultimediaKit::MetaData>();
|
||||
}
|
||||
|
||||
QVariant DirectShowMetaDataControl::extendedMetaData(const QString &) const
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QStringList DirectShowMetaDataControl::availableExtendedMetaData() const
|
||||
{
|
||||
return QStringList();
|
||||
}
|
||||
|
||||
void DirectShowMetaDataControl::updateGraph(IFilterGraph2 *graph, IBaseFilter *source)
|
||||
{
|
||||
if (m_content)
|
||||
m_content->Release();
|
||||
|
||||
if (!graph || graph->QueryInterface(
|
||||
IID_IAMMediaContent, reinterpret_cast<void **>(&m_content)) != S_OK) {
|
||||
m_content = 0;
|
||||
}
|
||||
|
||||
#ifdef QT_NO_WMSDK
|
||||
Q_UNUSED(source);
|
||||
#else
|
||||
if (m_headerInfo)
|
||||
m_headerInfo->Release();
|
||||
|
||||
m_headerInfo = com_cast<IWMHeaderInfo>(source, IID_IWMHeaderInfo);
|
||||
#endif
|
||||
// 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();
|
||||
#ifndef QT_NO_WMSDK
|
||||
emit metaDataAvailableChanged(m_content || m_headerInfo);
|
||||
#else
|
||||
emit metaDataAvailableChanged(m_content);
|
||||
#endif
|
||||
} else {
|
||||
QMetaDataReaderControl::customEvent(event);
|
||||
}
|
||||
}
|
||||
93
src/plugins/directshow/player/directshowmetadatacontrol.h
Normal file
93
src/plugins/directshow/player/directshowmetadatacontrol.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWMETADATACONTROL_H
|
||||
#define DIRECTSHOWMETADATACONTROL_H
|
||||
|
||||
#include <qmetadatareadercontrol.h>
|
||||
|
||||
#include "directshowglobal.h"
|
||||
|
||||
#include <qnetwork.h>
|
||||
|
||||
#ifndef QT_NO_WMSDK
|
||||
#include <wmsdk.h>
|
||||
#endif
|
||||
|
||||
#include <QtCore/qcoreevent.h>
|
||||
|
||||
class DirectShowPlayerService;
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
class DirectShowMetaDataControl : public QMetaDataReaderControl
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DirectShowMetaDataControl(QObject *parent = 0);
|
||||
~DirectShowMetaDataControl();
|
||||
|
||||
bool isMetaDataAvailable() const;
|
||||
|
||||
QVariant metaData(QtMultimediaKit::MetaData key) const;
|
||||
QList<QtMultimediaKit::MetaData> availableMetaData() const;
|
||||
|
||||
QVariant extendedMetaData(const QString &key) const;
|
||||
QStringList availableExtendedMetaData() const;
|
||||
|
||||
void updateGraph(IFilterGraph2 *graph, IBaseFilter *source);
|
||||
|
||||
protected:
|
||||
void customEvent(QEvent *event);
|
||||
|
||||
private:
|
||||
enum Event
|
||||
{
|
||||
MetaDataChanged = QEvent::User
|
||||
};
|
||||
|
||||
IAMMediaContent *m_content;
|
||||
#ifndef QT_NO_WMSDK
|
||||
IWMHeaderInfo *m_headerInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
134
src/plugins/directshow/player/directshowpinenum.cpp
Normal file
134
src/plugins/directshow/player/directshowpinenum.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowpinenum.h"
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
72
src/plugins/directshow/player/directshowpinenum.h
Normal file
72
src/plugins/directshow/player/directshowpinenum.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWPINENUM_H
|
||||
#define DIRECTSHOWPINENUM_H
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
405
src/plugins/directshow/player/directshowplayercontrol.cpp
Normal file
405
src/plugins/directshow/player/directshowplayercontrol.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowplayercontrol.h"
|
||||
|
||||
#include "directshowplayerservice.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
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::NoMedia)
|
||||
, m_error(QMediaPlayer::NoError)
|
||||
, m_streamTypes(0)
|
||||
, m_muteVolume(-1)
|
||||
, m_position(0)
|
||||
, 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 const_cast<qint64 &>(m_position) = 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 mediaChanged(m_media);
|
||||
emitPropertyChanges();
|
||||
}
|
||||
|
||||
void DirectShowPlayerControl::play()
|
||||
{
|
||||
if (m_status == QMediaPlayer::NoMedia)
|
||||
return;
|
||||
if (m_status == QMediaPlayer::InvalidMedia) {
|
||||
setMedia(m_media, m_stream);
|
||||
if (m_error != QMediaPlayer::NoError)
|
||||
return;
|
||||
}
|
||||
m_service->play();
|
||||
emit stateChanged(m_state = QMediaPlayer::PlayingState);
|
||||
}
|
||||
|
||||
void DirectShowPlayerControl::pause()
|
||||
{
|
||||
if (m_status == QMediaPlayer::NoMedia)
|
||||
return;
|
||||
if (m_status == QMediaPlayer::InvalidMedia) {
|
||||
setMedia(m_media, m_stream);
|
||||
if (m_error != QMediaPlayer::NoError)
|
||||
return;
|
||||
}
|
||||
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)) {
|
||||
emitPropertyChanges();
|
||||
|
||||
event->accept();
|
||||
} else {
|
||||
QMediaPlayerControl::customEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DirectShowPlayerControl::emitPropertyChanges()
|
||||
{
|
||||
int properties = m_updateProperties;
|
||||
m_updateProperties = 0;
|
||||
|
||||
if ((properties & ErrorProperty) && m_error != QMediaPlayer::NoError)
|
||||
emit error(m_error, m_errorString);
|
||||
|
||||
if (properties & PlaybackRateProperty)
|
||||
emit playbackRateChanged(m_playbackRate);
|
||||
|
||||
if (properties & StreamTypesProperty) {
|
||||
emit audioAvailableChanged(m_streamTypes & DirectShowPlayerService::AudioStream);
|
||||
emit videoAvailableChanged(m_streamTypes & DirectShowPlayerService::VideoStream);
|
||||
}
|
||||
|
||||
if (properties & PositionProperty)
|
||||
emit positionChanged(m_position);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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, IID_IBasicAudio);
|
||||
}
|
||||
|
||||
void DirectShowPlayerControl::updateError(QMediaPlayer::Error error, const QString &errorString)
|
||||
{
|
||||
m_error = error;
|
||||
m_errorString = errorString;
|
||||
|
||||
if (m_error != QMediaPlayer::NoError)
|
||||
scheduleUpdate(ErrorProperty);
|
||||
}
|
||||
|
||||
void DirectShowPlayerControl::updatePosition(qint64 position)
|
||||
{
|
||||
if (m_position != position) {
|
||||
m_position = position;
|
||||
|
||||
scheduleUpdate(PositionProperty);
|
||||
}
|
||||
}
|
||||
146
src/plugins/directshow/player/directshowplayercontrol.h
Normal file
146
src/plugins/directshow/player/directshowplayercontrol.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWPLAYERCONTROL_H
|
||||
#define DIRECTSHOWPLAYERCONTROL_H
|
||||
|
||||
#include "qmediacontent.h"
|
||||
#include "qmediaplayercontrol.h"
|
||||
|
||||
#include <QtCore/qcoreevent.h>
|
||||
|
||||
#include "directshowplayerservice.h"
|
||||
|
||||
QT_USE_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);
|
||||
void updateError(QMediaPlayer::Error error, const QString &errorString);
|
||||
void updatePosition(qint64 position);
|
||||
|
||||
protected:
|
||||
void customEvent(QEvent *event);
|
||||
|
||||
private:
|
||||
enum Properties
|
||||
{
|
||||
StateProperty = 0x01,
|
||||
StatusProperty = 0x02,
|
||||
StreamTypesProperty = 0x04,
|
||||
DurationProperty = 0x08,
|
||||
PlaybackRateProperty = 0x10,
|
||||
SeekableProperty = 0x20,
|
||||
ErrorProperty = 0x40,
|
||||
PositionProperty = 0x80
|
||||
};
|
||||
|
||||
enum Event
|
||||
{
|
||||
PropertiesChanged = QEvent::User
|
||||
};
|
||||
|
||||
void scheduleUpdate(int properties);
|
||||
void emitPropertyChanges();
|
||||
|
||||
DirectShowPlayerService *m_service;
|
||||
IBasicAudio *m_audio;
|
||||
QIODevice *m_stream;
|
||||
int m_updateProperties;
|
||||
QMediaPlayer::State m_state;
|
||||
QMediaPlayer::MediaStatus m_status;
|
||||
QMediaPlayer::Error m_error;
|
||||
int m_streamTypes;
|
||||
int m_muteVolume;
|
||||
qint64 m_position;
|
||||
qint64 m_duration;
|
||||
qreal m_playbackRate;
|
||||
bool m_seekable;
|
||||
QMediaContent m_media;
|
||||
QString m_errorString;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
1408
src/plugins/directshow/player/directshowplayerservice.cpp
Normal file
1408
src/plugins/directshow/player/directshowplayerservice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
219
src/plugins/directshow/player/directshowplayerservice.h
Normal file
219
src/plugins/directshow/player/directshowplayerservice.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWPLAYERSERVICE_H
|
||||
#define DIRECTSHOWPLAYERSERVICE_H
|
||||
|
||||
#include "qmediaplayer.h"
|
||||
#include "qmediaresource.h"
|
||||
#include "qmediaservice.h"
|
||||
#include "qmediatimerange.h"
|
||||
|
||||
#include "directshoweventloop.h"
|
||||
#include "directshowglobal.h"
|
||||
|
||||
#include <QtCore/qcoreevent.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qurl.h>
|
||||
#include <QtCore/qwaitcondition.h>
|
||||
|
||||
class DirectShowAudioEndpointControl;
|
||||
class DirectShowMetaDataControl;
|
||||
class DirectShowPlayerControl;
|
||||
class DirectShowVideoRendererControl;
|
||||
#ifndef Q_WS_SIMULATOR
|
||||
class Vmr9VideoWindowControl;
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMediaContent;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
class DirectShowPlayerService : public QMediaService
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum StreamType
|
||||
{
|
||||
AudioStream = 0x01,
|
||||
VideoStream = 0x02
|
||||
};
|
||||
|
||||
DirectShowPlayerService(QObject *parent = 0);
|
||||
~DirectShowPlayerService();
|
||||
|
||||
QMediaControl* requestControl(const char *name);
|
||||
void releaseControl(QMediaControl *control);
|
||||
|
||||
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();
|
||||
|
||||
private:
|
||||
void releaseGraph();
|
||||
void updateStatus();
|
||||
|
||||
int findStreamTypes(IBaseFilter *source) const;
|
||||
int findStreamType(IPin *pin) const;
|
||||
|
||||
bool isConnected(IBaseFilter *filter, PIN_DIRECTION direction) const;
|
||||
IBaseFilter *getConnected(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 doStop(QMutexLocker *locker);
|
||||
void doReleaseAudioOutput(QMutexLocker *locker);
|
||||
void doReleaseVideoOutput(QMutexLocker *locker);
|
||||
void doReleaseGraph(QMutexLocker *locker);
|
||||
|
||||
void graphEvent(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,
|
||||
ReleaseGraph = 0x1000,
|
||||
ReleaseAudioOutput = 0x2000,
|
||||
ReleaseVideoOutput = 0x4000,
|
||||
ReleaseFilters = ReleaseGraph | ReleaseAudioOutput | ReleaseVideoOutput
|
||||
};
|
||||
|
||||
enum Event
|
||||
{
|
||||
FinalizedLoad = QEvent::User,
|
||||
Error,
|
||||
RateChange,
|
||||
Started,
|
||||
Paused,
|
||||
DurationChange,
|
||||
StatusChange,
|
||||
EndOfMedia,
|
||||
PositionChange
|
||||
};
|
||||
|
||||
enum GraphStatus
|
||||
{
|
||||
NoMedia,
|
||||
Loading,
|
||||
Loaded,
|
||||
InvalidMedia
|
||||
};
|
||||
|
||||
DirectShowPlayerControl *m_playerControl;
|
||||
DirectShowMetaDataControl *m_metaDataControl;
|
||||
DirectShowVideoRendererControl *m_videoRendererControl;
|
||||
#ifndef Q_WS_SIMULATOR
|
||||
Vmr9VideoWindowControl *m_videoWindowControl;
|
||||
#endif
|
||||
DirectShowAudioEndpointControl *m_audioEndpointControl;
|
||||
|
||||
QThread *m_taskThread;
|
||||
DirectShowEventLoop *m_loop;
|
||||
int m_pendingTasks;
|
||||
int m_executingTask;
|
||||
int m_executedTasks;
|
||||
HANDLE m_taskHandle;
|
||||
HANDLE m_eventHandle;
|
||||
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;
|
||||
bool m_atEnd;
|
||||
QMediaTimeRange m_playbackRange;
|
||||
QUrl m_url;
|
||||
QMediaResourceList m_resources;
|
||||
QString m_errorString;
|
||||
QMutex m_mutex;
|
||||
|
||||
friend class DirectShowPlayerServiceThread;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
437
src/plugins/directshow/player/directshowsamplescheduler.cpp
Normal file
437
src/plugins/directshow/player/directshowsamplescheduler.cpp
Normal file
@@ -0,0 +1,437 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowsamplescheduler.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qcoreevent.h>
|
||||
|
||||
class DirectShowTimedSample
|
||||
{
|
||||
public:
|
||||
DirectShowTimedSample(IMediaSample *sample)
|
||||
: m_next(0)
|
||||
, m_sample(sample)
|
||||
, m_cookie(0)
|
||||
, m_lastSample(false)
|
||||
{
|
||||
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;
|
||||
|
||||
bool isLast() const { return m_lastSample; }
|
||||
void setLast() { m_lastSample = true; }
|
||||
|
||||
private:
|
||||
DirectShowTimedSample *m_next;
|
||||
IMediaSample *m_sample;
|
||||
DWORD_PTR m_cookie;
|
||||
bool m_lastSample;
|
||||
};
|
||||
|
||||
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(¤tTime) == S_OK)
|
||||
return currentTime >= sampleStartTime;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DirectShowSampleScheduler::DirectShowSampleScheduler(IUnknown *pin, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_pin(pin)
|
||||
, m_clock(0)
|
||||
, m_allocator(0)
|
||||
, m_head(0)
|
||||
, m_tail(0)
|
||||
, m_maximumSamples(1)
|
||||
, m_state(Stopped)
|
||||
, m_startTime(0)
|
||||
, m_timeoutEvent(::CreateEvent(0, 0, 0, 0))
|
||||
, m_flushEvent(::CreateEvent(0, 0, 0, 0))
|
||||
{
|
||||
m_semaphore.release(m_maximumSamples);
|
||||
}
|
||||
|
||||
DirectShowSampleScheduler::~DirectShowSampleScheduler()
|
||||
{
|
||||
::CloseHandle(m_timeoutEvent);
|
||||
::CloseHandle(m_flushEvent);
|
||||
|
||||
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.
|
||||
QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
|
||||
} else {
|
||||
locker.unlock();
|
||||
HANDLE handles[] = { m_flushEvent, m_timeoutEvent };
|
||||
DWORD result = ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
locker.relock();
|
||||
|
||||
if (result == WAIT_OBJECT_0 + 1)
|
||||
QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
|
||||
}
|
||||
} else if (m_tail == m_head) {
|
||||
// If this is the first frame make it available.
|
||||
QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
|
||||
|
||||
if (m_state == Paused) {
|
||||
::ResetEvent(m_timeoutEvent);
|
||||
|
||||
locker.unlock();
|
||||
HANDLE handles[] = { m_flushEvent, m_timeoutEvent };
|
||||
::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
|
||||
locker.relock();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!(m_state & Flushing))
|
||||
::ResetEvent(m_flushEvent);
|
||||
|
||||
if (!m_head)
|
||||
::SetEvent(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);
|
||||
|
||||
if (!(m_state & Flushing))
|
||||
::ResetEvent(m_flushEvent);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
::SetEvent(m_flushEvent);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
::SetEvent(m_flushEvent);
|
||||
} else {
|
||||
m_state &= ~Flushing;
|
||||
|
||||
if (m_state != Stopped)
|
||||
::ResetEvent(m_flushEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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(bool *eos)
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (m_head && m_head->isReady(m_clock)) {
|
||||
IMediaSample *sample = m_head->sample();
|
||||
sample->AddRef();
|
||||
|
||||
*eos = m_head->isLast();
|
||||
|
||||
m_head = m_head->remove();
|
||||
|
||||
if (!m_head)
|
||||
m_tail = 0;
|
||||
|
||||
m_semaphore.release(1);
|
||||
|
||||
return sample;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectShowSampleScheduler::scheduleEndOfStream()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (m_tail) {
|
||||
m_tail->setLast();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DirectShowSampleScheduler::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::UpdateRequest) {
|
||||
emit sampleReady();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return QObject::event(event);
|
||||
}
|
||||
}
|
||||
117
src/plugins/directshow/player/directshowsamplescheduler.h
Normal file
117
src/plugins/directshow/player/directshowsamplescheduler.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWSAMPLESCHEDULER_H
|
||||
#define DIRECTSHOWSAMPLESCHEDULER_H
|
||||
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qsemaphore.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
class DirectShowTimedSample;
|
||||
|
||||
class DirectShowSampleScheduler : public QObject, 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);
|
||||
bool scheduleEndOfStream();
|
||||
|
||||
IMediaSample *takeSample(bool *eos);
|
||||
|
||||
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;
|
||||
HANDLE m_flushEvent;
|
||||
QSemaphore m_semaphore;
|
||||
QMutex m_mutex;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "directshowvideorenderercontrol.h"
|
||||
|
||||
#include "videosurfacefilter.h"
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef DIRECTSHOWVIDEORENDERERCONTROL_H
|
||||
#define DIRECTSHOWVIDEORENDERERCONTROL_H
|
||||
|
||||
#include "qvideorenderercontrol.h"
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
class DirectShowEventLoop;
|
||||
class VideoSurfaceFilter;
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
86
src/plugins/directshow/player/mediasamplevideobuffer.cpp
Normal file
86
src/plugins/directshow/player/mediasamplevideobuffer.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "mediasamplevideobuffer.h"
|
||||
|
||||
MediaSampleVideoBuffer::MediaSampleVideoBuffer(IMediaSample *sample, int bytesPerLine)
|
||||
: QAbstractVideoBuffer(NoHandle)
|
||||
, m_sample(sample)
|
||||
, m_bytesPerLine(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;
|
||||
}
|
||||
69
src/plugins/directshow/player/mediasamplevideobuffer.h
Normal file
69
src/plugins/directshow/player/mediasamplevideobuffer.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MEDIASAMPLEVIDEOBUFFER_H
|
||||
#define MEDIASAMPLEVIDEOBUFFER_H
|
||||
|
||||
#include <qabstractvideobuffer.h>
|
||||
|
||||
#include <dshow.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
47
src/plugins/directshow/player/player.pri
Normal file
47
src/plugins/directshow/player/player.pri
Normal file
@@ -0,0 +1,47 @@
|
||||
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/directshowvideorenderercontrol.h \
|
||||
$$PWD/mediasamplevideobuffer.h \
|
||||
$$PWD/videosurfacefilter.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/directshowvideorenderercontrol.cpp \
|
||||
$$PWD/mediasamplevideobuffer.cpp \
|
||||
$$PWD/videosurfacefilter.cpp
|
||||
|
||||
!simulator {
|
||||
HEADERS += \
|
||||
$$PWD/vmr9videowindowcontrol.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/vmr9videowindowcontrol.cpp
|
||||
}
|
||||
|
||||
LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 -lgdi32
|
||||
|
||||
631
src/plugins/directshow/player/videosurfacefilter.cpp
Normal file
631
src/plugins/directshow/player/videosurfacefilter.cpp
Normal file
@@ -0,0 +1,631 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "videosurfacefilter.h"
|
||||
|
||||
#include "directshoweventloop.h"
|
||||
#include "directshowglobal.h"
|
||||
#include "directshowpinenum.h"
|
||||
#include "mediasamplevideobuffer.h"
|
||||
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qcoreevent.h>
|
||||
#include <QtCore/qthread.h>
|
||||
#include <qabstractvideosurface.h>
|
||||
|
||||
#include <initguid.h>
|
||||
|
||||
// { 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)
|
||||
{
|
||||
// 2dd74950-a890-11d1-abe8-00a0c905f375
|
||||
static const GUID iid_IAmFilterMiscFlags = {
|
||||
0x2dd74950, 0xa890, 0x11d1, {0xab, 0xe8, 0x00, 0xa0, 0xc9, 0x05, 0xf3, 0x75} };
|
||||
|
||||
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->isFormatSupported(m_surfaceFormat)) {
|
||||
return VFW_E_TYPE_NOT_ACCEPTED;
|
||||
}
|
||||
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()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
|
||||
if (!m_sampleScheduler.scheduleEndOfStream()) {
|
||||
if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph, IID_IMediaEventSink)) {
|
||||
sink->Notify(
|
||||
EC_COMPLETE,
|
||||
S_OK,
|
||||
reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this)));
|
||||
sink->Release();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// MEDIASUBTYPE_None;
|
||||
static const GUID none = {
|
||||
0xe436eb8e, 0x524f, 0x11ce, {0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70} };
|
||||
|
||||
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 != none)
|
||||
mediaTypes.append(type);
|
||||
}
|
||||
|
||||
setMediaTypes(mediaTypes);
|
||||
}
|
||||
|
||||
void VideoSurfaceFilter::sampleReady()
|
||||
{
|
||||
bool eos = false;
|
||||
|
||||
IMediaSample *sample = m_sampleScheduler.takeSample(&eos);
|
||||
|
||||
if (sample) {
|
||||
m_surface->present(QVideoFrame(
|
||||
new MediaSampleVideoBuffer(sample, m_bytesPerLine),
|
||||
m_surfaceFormat.frameSize(),
|
||||
m_surfaceFormat.pixelFormat()));
|
||||
|
||||
sample->Release();
|
||||
|
||||
if (eos) {
|
||||
if (IMediaEventSink *sink = com_cast<IMediaEventSink>(m_graph, IID_IMediaEventSink)) {
|
||||
sink->Notify(
|
||||
EC_COMPLETE,
|
||||
S_OK,
|
||||
reinterpret_cast<LONG_PTR>(static_cast<IBaseFilter *>(this)));
|
||||
sink->Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
176
src/plugins/directshow/player/videosurfacefilter.h
Normal file
176
src/plugins/directshow/player/videosurfacefilter.h
Normal file
@@ -0,0 +1,176 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef VIDEOSURFACEFILTER_H
|
||||
#define VIDEOSURFACEFILTER_H
|
||||
|
||||
#include "directshowglobal.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_NAMESPACE
|
||||
class QAbstractVideoSurface;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
329
src/plugins/directshow/player/vmr9videowindowcontrol.cpp
Normal file
329
src/plugins/directshow/player/vmr9videowindowcontrol.cpp
Normal file
@@ -0,0 +1,329 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "vmr9videowindowcontrol.h"
|
||||
|
||||
#include "directshowglobal.h"
|
||||
|
||||
Vmr9VideoWindowControl::Vmr9VideoWindowControl(QObject *parent)
|
||||
: QVideoWindowControl(parent)
|
||||
, m_filter(com_new<IBaseFilter>(CLSID_VideoMixingRenderer9, IID_IBaseFilter))
|
||||
, m_windowId(0)
|
||||
, m_dirtyValues(0)
|
||||
, m_aspectRatioMode(Qt::KeepAspectRatio)
|
||||
, m_brightness(0)
|
||||
, m_contrast(0)
|
||||
, m_hue(0)
|
||||
, m_saturation(0)
|
||||
, m_fullScreen(false)
|
||||
{
|
||||
if (IVMRFilterConfig9 *config = com_cast<IVMRFilterConfig9>(m_filter, IID_IVMRFilterConfig9)) {
|
||||
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 (QWidget *widget = QWidget::find(m_windowId)) {
|
||||
const QColor color = widget->palette().color(QPalette::Window);
|
||||
|
||||
m_windowColor = RGB(color.red(), color.green(), color.blue());
|
||||
}
|
||||
|
||||
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
|
||||
m_filter, IID_IVMRWindowlessControl9)) {
|
||||
control->SetVideoClippingWindow(m_windowId);
|
||||
control->SetBorderColor(m_windowColor);
|
||||
control->Release();
|
||||
}
|
||||
}
|
||||
|
||||
QRect Vmr9VideoWindowControl::displayRect() const
|
||||
{
|
||||
return m_displayRect;
|
||||
}
|
||||
|
||||
void Vmr9VideoWindowControl::setDisplayRect(const QRect &rect)
|
||||
{
|
||||
m_displayRect = rect;
|
||||
|
||||
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
|
||||
m_filter, IID_IVMRWindowlessControl9)) {
|
||||
RECT sourceRect = { 0, 0, 0, 0 };
|
||||
RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 };
|
||||
|
||||
control->GetNativeVideoSize(&sourceRect.right, &sourceRect.bottom, 0, 0);
|
||||
|
||||
if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
|
||||
QSize clippedSize = rect.size();
|
||||
clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio);
|
||||
|
||||
sourceRect.left = (sourceRect.right - clippedSize.width()) / 2;
|
||||
sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2;
|
||||
sourceRect.right = sourceRect.left + clippedSize.width();
|
||||
sourceRect.bottom = sourceRect.top + clippedSize.height();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
PAINTSTRUCT paint;
|
||||
|
||||
if (HDC dc = ::BeginPaint(m_windowId, &paint)) {
|
||||
HRESULT hr = E_FAIL;
|
||||
|
||||
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
|
||||
m_filter, IID_IVMRWindowlessControl9)) {
|
||||
hr = control->RepaintVideo(m_windowId, dc);
|
||||
control->Release();
|
||||
}
|
||||
|
||||
if (!SUCCEEDED(hr)) {
|
||||
HPEN pen = ::CreatePen(PS_SOLID, 1, m_windowColor);
|
||||
HBRUSH brush = ::CreateSolidBrush(m_windowColor);
|
||||
::SelectObject(dc, pen);
|
||||
::SelectObject(dc, brush);
|
||||
|
||||
::Rectangle(
|
||||
dc,
|
||||
m_displayRect.left(),
|
||||
m_displayRect.top(),
|
||||
m_displayRect.right() + 1,
|
||||
m_displayRect.bottom() + 1);
|
||||
|
||||
::DeleteObject(pen);
|
||||
::DeleteObject(brush);
|
||||
}
|
||||
::EndPaint(m_windowId, &paint);
|
||||
}
|
||||
}
|
||||
|
||||
QSize Vmr9VideoWindowControl::nativeSize() const
|
||||
{
|
||||
QSize size;
|
||||
|
||||
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
|
||||
m_filter, IID_IVMRWindowlessControl9)) {
|
||||
LONG width;
|
||||
LONG height;
|
||||
|
||||
if (control->GetNativeVideoSize(&width, &height, 0, 0) == S_OK)
|
||||
size = QSize(width, height);
|
||||
control->Release();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
Qt::AspectRatioMode Vmr9VideoWindowControl::aspectRatioMode() const
|
||||
{
|
||||
return m_aspectRatioMode;
|
||||
}
|
||||
|
||||
void Vmr9VideoWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
|
||||
{
|
||||
m_aspectRatioMode = mode;
|
||||
|
||||
if (IVMRWindowlessControl9 *control = com_cast<IVMRWindowlessControl9>(
|
||||
m_filter, IID_IVMRWindowlessControl9)) {
|
||||
switch (mode) {
|
||||
case Qt::IgnoreAspectRatio:
|
||||
control->SetAspectRatioMode(VMR9ARMode_None);
|
||||
break;
|
||||
case Qt::KeepAspectRatio:
|
||||
control->SetAspectRatioMode(VMR9ARMode_LetterBox);
|
||||
break;
|
||||
case Qt::KeepAspectRatioByExpanding:
|
||||
control->SetAspectRatioMode(VMR9ARMode_LetterBox);
|
||||
setDisplayRect(m_displayRect);
|
||||
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, IID_IVMRMixerControl9)) {
|
||||
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;
|
||||
}
|
||||
108
src/plugins/directshow/player/vmr9videowindowcontrol.h
Normal file
108
src/plugins/directshow/player/vmr9videowindowcontrol.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
** All rights reserved.
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
** This file is part of the Qt Mobility Components.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** No Commercial Usage
|
||||
** This file contains pre-release code and may not be distributed.
|
||||
** You may use this file in accordance with the terms and conditions
|
||||
** contained in the Technology Preview License Agreement accompanying
|
||||
** this package.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 2.1 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef VMR9VIDEOWINDOWCONTROL_H
|
||||
#define VMR9VIDEOWINDOWCONTROL_H
|
||||
|
||||
#include "qvideowindowcontrol.h"
|
||||
|
||||
#include <dshow.h>
|
||||
#include <d3d9.h>
|
||||
#include <vmr9.h>
|
||||
|
||||
QT_USE_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;
|
||||
|
||||
Qt::AspectRatioMode aspectRatioMode() const;
|
||||
void setAspectRatioMode(Qt::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;
|
||||
COLORREF m_windowColor;
|
||||
DWORD m_dirtyValues;
|
||||
Qt::AspectRatioMode m_aspectRatioMode;
|
||||
QRect m_displayRect;
|
||||
int m_brightness;
|
||||
int m_contrast;
|
||||
int m_hue;
|
||||
int m_saturation;
|
||||
bool m_fullScreen;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user