diff options
author | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
---|---|---|
committer | Michael Goddard <michael.goddard@nokia.com> | 2011-06-29 13:38:46 +1000 |
commit | 2a34e88c1e1ced28e75c487cd13402e1c9cf9fa3 (patch) | |
tree | e6c1b770c5c47212792a1f9344fa034ea3e54c44 /src/plugins/directshow/camera |
Initial copy of QtMultimediaKit.
Comes from original repo, with SHA1:
2c82d5611655e5967f5c5095af50c0991c4378b2
Diffstat (limited to 'src/plugins/directshow/camera')
16 files changed, 3001 insertions, 0 deletions
diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri new file mode 100644 index 000000000..42f5999a2 --- /dev/null +++ b/src/plugins/directshow/camera/camera.pri @@ -0,0 +1,31 @@ +INCLUDEPATH += $$PWD + +DEFINES += QMEDIA_DIRECTSHOW_CAMERA + +win32-g++: DEFINES += QT_NO_WMSDK + +win32: DEFINES += _CRT_SECURE_NO_WARNINGS + +HEADERS += \ + $$PWD/dscameraservice.h \ + $$PWD/dscameracontrol.h \ + $$PWD/dsvideorenderer.h \ + $$PWD/dsvideodevicecontrol.h \ + $$PWD/dsimagecapturecontrol.h \ + $$PWD/dscamerasession.h \ + $$PWD/dsvideowidgetcontrol.h \ + $$PWD/dscameraservice.h \ + $$PWD/directshowglobal.h + + +SOURCES += \ + $$PWD/dscameraservice.cpp \ + $$PWD/dscameracontrol.cpp \ + $$PWD/dsvideorenderer.cpp \ + $$PWD/dsvideodevicecontrol.cpp \ + $$PWD/dsimagecapturecontrol.cpp \ + $$PWD/dscamerasession.cpp \ + $$PWD/dsvideowidgetcontrol.cpp + +INCLUDEPATH += $(DXSDK_DIR)/include +LIBS += -lstrmiids -ldmoguids -luuid -lmsdmo -lole32 -loleaut32 diff --git a/src/plugins/directshow/camera/directshowglobal.h b/src/plugins/directshow/camera/directshowglobal.h new file mode 100644 index 000000000..76c143798 --- /dev/null +++ b/src/plugins/directshow/camera/directshowglobal.h @@ -0,0 +1,236 @@ +/**************************************************************************** +** +** 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> + +DEFINE_GUID(MEDIASUBTYPE_I420, + 0x30323449,0x0000,0x0010,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71); + +extern const GUID MEDIASUBTYPE_RGB24; +extern const GUID MEDIASUBTYPE_RGB32; +extern const GUID MEDIASUBTYPE_YUY2; +extern const GUID MEDIASUBTYPE_MJPG; +extern const GUID MEDIASUBTYPE_RGB555; +extern const GUID MEDIASUBTYPE_YVU9; +extern const GUID MEDIASUBTYPE_UYVY; +extern const GUID PIN_CATEGORY_CAPTURE; +extern const GUID PIN_CATEGORY_PREVIEW; + +extern const IID IID_IPropertyBag; +extern const IID IID_ISampleGrabber; +extern const IID IID_ICaptureGraphBuilder2; +extern const IID IID_IAMStreamConfig; + + +extern const CLSID CLSID_CVidCapClassManager; +extern const CLSID CLSID_VideoInputDeviceCategory; +extern const CLSID CLSID_SampleGrabber; +extern const CLSID CLSID_CaptureGraphBuilder2; + +#define SAFE_RELEASE(x) { if(x) x->Release(); x = NULL; } + +typedef struct IFileSinkFilter *LPFILESINKFILTER; +typedef struct IAMCopyCaptureFileProgress *LPAMCOPYCAPTUREFILEPROGRESS; + +#ifndef __ICaptureGraphBuilder2_INTERFACE_DEFINED__ +#define __ICaptureGraphBuilder2_INTERFACE_DEFINED__ +struct ICaptureGraphBuilder2 : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetFiltergraph( + /* [in] */ IGraphBuilder *pfg) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFiltergraph( + /* [out] */ IGraphBuilder **ppfg) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetOutputFileName( + /* [in] */ const GUID *pType, + /* [in] */ LPCOLESTR lpstrFile, + /* [out] */ IBaseFilter **ppf, + /* [out] */ IFileSinkFilter **ppSink) = 0; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE FindInterface( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IBaseFilter *pf, + /* [in] */ REFIID riid, + /* [out] */ void **ppint) = 0; + + virtual HRESULT STDMETHODCALLTYPE RenderStream( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IUnknown *pSource, + /* [in] */ IBaseFilter *pfCompressor, + /* [in] */ IBaseFilter *pfRenderer) = 0; + + virtual HRESULT STDMETHODCALLTYPE ControlStream( + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ IBaseFilter *pFilter, + /* [in] */ REFERENCE_TIME *pstart, + /* [in] */ REFERENCE_TIME *pstop, + /* [in] */ WORD wStartCookie, + /* [in] */ WORD wStopCookie) = 0; + + virtual HRESULT STDMETHODCALLTYPE AllocCapFile( + /* [in] */ LPCOLESTR lpstr, + /* [in] */ DWORDLONG dwlSize) = 0; + + virtual HRESULT STDMETHODCALLTYPE CopyCaptureFile( + /* [in] */ LPOLESTR lpwstrOld, + /* [in] */ LPOLESTR lpwstrNew, + /* [in] */ int fAllowEscAbort, + /* [in] */ IAMCopyCaptureFileProgress *pCallback) = 0; + + virtual HRESULT STDMETHODCALLTYPE FindPin( + /* [in] */ IUnknown *pSource, + /* [in] */ PIN_DIRECTION pindir, + /* [in] */ const GUID *pCategory, + /* [in] */ const GUID *pType, + /* [in] */ BOOL fUnconnected, + /* [in] */ int num, + /* [out] */ IPin **ppPin) = 0; + +}; +#endif + +#ifndef __IAMStreamConfig_INTERFACE_DEFINED__ +#define __IAMStreamConfig_INTERFACE_DEFINED__ +struct IAMStreamConfig : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetFormat( + /* [in] */ AM_MEDIA_TYPE *pmt) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetFormat( + /* [out] */ AM_MEDIA_TYPE **ppmt) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities( + /* [out] */ int *piCount, + /* [out] */ int *piSize) = 0; + + virtual HRESULT STDMETHODCALLTYPE GetStreamCaps( + /* [in] */ int iIndex, + /* [out] */ AM_MEDIA_TYPE **ppmt, + /* [out] */ BYTE *pSCC) = 0; + +}; +#endif + +#ifndef __IErrorLog_INTERFACE_DEFINED__ +#define __IErrorLog_INTERFACE_DEFINED__ +struct IErrorLog : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE AddError( + /* [in] */ LPCOLESTR pszPropName, + /* [in] */ EXCEPINFO *pExcepInfo) = 0; + + }; +#endif + +#ifndef __IPropertyBag_INTERFACE_DEFINED__ +#define __IPropertyBag_INTERFACE_DEFINED__ +struct IPropertyBag : public IUnknown +{ +public: + virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read( + /* [in] */ LPCOLESTR pszPropName, + /* [out][in] */ VARIANT *pVar, + /* [in] */ IErrorLog *pErrorLog) = 0; + + virtual HRESULT STDMETHODCALLTYPE Write( + /* [in] */ LPCOLESTR pszPropName, + /* [in] */ VARIANT *pVar) = 0; + +}; +#endif + +typedef struct IMediaSample *LPMEDIASAMPLE; + +EXTERN_C const IID IID_ISampleGrabberCB; + +#ifndef __ISampleGrabberCB_INTERFACE_DEFINED__ +#define __ISampleGrabberCB_INTERFACE_DEFINED__ + +#undef INTERFACE +#define INTERFACE ISampleGrabberCB +DECLARE_INTERFACE_(ISampleGrabberCB, IUnknown) +{ +// STDMETHOD(QueryInterface) (THIS_ const GUID *, void **) PURE; + STDMETHOD(QueryInterface) (THIS_ REFIID riid, void **) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + STDMETHOD_(HRESULT, SampleCB) (THIS_ double, LPMEDIASAMPLE) PURE; + STDMETHOD_(HRESULT, BufferCB) (THIS_ double, BYTE *, long) PURE; +}; +#undef INTERFACE + +#endif + + +#ifndef __ISampleGrabber_INTERFACE_DEFINED__ +#define __ISampleGrabber_INTERFACE_DEFINED__ + +#define INTERFACE ISampleGrabber +DECLARE_INTERFACE_(ISampleGrabber,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetOneShot)(THIS_ BOOL) PURE; + STDMETHOD(SetMediaType)(THIS_ const AM_MEDIA_TYPE*) PURE; + STDMETHOD(GetConnectedMediaType)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(SetBufferSamples)(THIS_ BOOL) PURE; + STDMETHOD(GetCurrentBuffer)(THIS_ long*,long*) PURE; + STDMETHOD(GetCurrentSample)(THIS_ IMediaSample**) PURE; + STDMETHOD(SetCallback)(THIS_ ISampleGrabberCB *,long) PURE; +}; +#undef INTERFACE +#endif + + +#endif diff --git a/src/plugins/directshow/camera/dscameracontrol.cpp b/src/plugins/directshow/camera/dscameracontrol.cpp new file mode 100644 index 000000000..b09064c2b --- /dev/null +++ b/src/plugins/directshow/camera/dscameracontrol.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QtCore/qdebug.h> + +#include "dscameracontrol.h" +#include "dscameraservice.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSCameraControl::DSCameraControl(QObject *parent) + :QCameraControl(parent), m_captureMode(QCamera::CaptureStillImage) +{ + m_session = qobject_cast<DSCameraSession*>(parent); + connect(m_session, SIGNAL(stateChanged(QCamera::State)),this, SIGNAL(stateChanged(QCamera::State))); +} + +DSCameraControl::~DSCameraControl() +{ +} + +void DSCameraControl::setState(QCamera::State state) +{ + switch (state) { + case QCamera::ActiveState: + start(); + break; + case QCamera::UnloadedState: /* fall through */ + case QCamera::LoadedState: + stop(); + break; + } +} + +bool DSCameraControl::isCaptureModeSupported(QCamera::CaptureMode mode) const +{ + bool bCaptureSupported = false; + switch (mode) { + case QCamera::CaptureStillImage: + bCaptureSupported = true; + break; + case QCamera::CaptureVideo: + bCaptureSupported = false; + break; + } + return bCaptureSupported; +} + +void DSCameraControl::start() +{ + m_session->record(); +} + +void DSCameraControl::stop() +{ + m_session->stop(); +} + +QCamera::State DSCameraControl::state() const +{ + return (QCamera::State)m_session->state(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameracontrol.h b/src/plugins/directshow/camera/dscameracontrol.h new file mode 100644 index 000000000..9b20563d2 --- /dev/null +++ b/src/plugins/directshow/camera/dscameracontrol.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSCAMERACONTROL_H +#define DSCAMERACONTROL_H + +#include <QtCore/qobject.h> +#include <qcameracontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSCameraService; +class DSCameraSession; + + +class DSCameraControl : public QCameraControl +{ + Q_OBJECT +public: + DSCameraControl(QObject *parent = 0); + ~DSCameraControl(); + + void start(); + void stop(); + QCamera::State state() const; + + QCamera::CaptureMode captureMode() const { return m_captureMode; } + void setCaptureMode(QCamera::CaptureMode mode) + { + if (m_captureMode != mode) { + m_captureMode = mode; + emit captureModeChanged(mode); + } + } + + void setState(QCamera::State state); + + QCamera::Status status() const { return QCamera::UnavailableStatus; } + bool isCaptureModeSupported(QCamera::CaptureMode mode) const; + bool canChangeProperty(PropertyChangeType /* changeType */, QCamera::Status /* status */) const {return false; } + +private: + DSCameraSession *m_session; + DSCameraService *m_service; + QCamera::CaptureMode m_captureMode; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif + + diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp new file mode 100644 index 000000000..9d73da02c --- /dev/null +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QtCore/qvariant.h> +#include <QtCore/qdebug.h> +#include <QtGui/qwidget.h> +#include <QVideoWidgetControl.h> + + +#include "dscameraservice.h" +#include "dscameracontrol.h" +#include "dscamerasession.h" +#include "dsvideorenderer.h" +#include "dsvideodevicecontrol.h" +#include "dsimagecapturecontrol.h" +#include "dsvideowidgetcontrol.h" + +QT_BEGIN_NAMESPACE + +DSCameraService::DSCameraService(QObject *parent): + QMediaService(parent) +{ + m_session = new DSCameraSession(this); + + m_control = new DSCameraControl(m_session); + + m_videoDevice = new DSVideoDeviceControl(m_session); + + m_videoRenderer = new DSVideoRendererControl(m_session, this); + + m_imageCapture = new DSImageCaptureControl(m_session); + + m_viewFinderWidget = new DSVideoWidgetControl(m_session); + + m_device = QByteArray("default"); +} + +DSCameraService::~DSCameraService() +{ + delete m_control; + delete m_videoDevice; + delete m_videoRenderer; + delete m_imageCapture; + delete m_viewFinderWidget; + delete m_session; +} + +QMediaControl* DSCameraService::requestControl(const char *name) +{ + if(qstrcmp(name,QCameraControl_iid) == 0) + return m_control; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCapture; + + if (qstrcmp(name, QVideoWidgetControl_iid) == 0) { + if (m_viewFinderWidget) { + return m_viewFinderWidget; + } + } + + if(qstrcmp(name,QVideoRendererControl_iid) == 0) + return m_videoRenderer; + + if(qstrcmp(name,QVideoDeviceControl_iid) == 0) + return m_videoDevice; + + return 0; +} + +void DSCameraService::releaseControl(QMediaControl *control) +{ + // Implemented as a singleton, so we do nothing. +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h new file mode 100644 index 000000000..e8a9450fb --- /dev/null +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSCAMERASERVICE_H +#define DSCAMERASERVICE_H + +#include <QtCore/qobject.h> + +#include <qmediaservice.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSCameraControl; +class DSCameraSession; +class DSVideoOutputControl; +class DSVideoDeviceControl; +class DSVideoRendererControl; +class DSImageCaptureControl; +class DSVideoWidgetControl; + + +class DSCameraService : public QMediaService +{ + Q_OBJECT + +public: + DSCameraService(QObject *parent = 0); + ~DSCameraService(); + + virtual QMediaControl* requestControl(const char *name); + virtual void releaseControl(QMediaControl *control); + +private: + DSCameraControl *m_control; + DSCameraSession *m_session; + DSVideoOutputControl *m_videoOutput; + DSVideoWidgetControl *m_viewFinderWidget; + DSVideoDeviceControl *m_videoDevice; + DSVideoRendererControl *m_videoRenderer; + DSImageCaptureControl *m_imageCapture; + QByteArray m_device; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp new file mode 100644 index 000000000..a08fb318f --- /dev/null +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -0,0 +1,1160 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QtCore/qdebug.h> +#include <QWidget> +#include <QFile> +#include <QtMultimedia/qabstractvideobuffer.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#include "dscamerasession.h" +#include "dsvideorenderer.h" +#include "directshowglobal.h" + +QT_BEGIN_NAMESPACE + +// If frames come in quicker than we display them, we allow the queue to build +// up to this number before we start dropping them. +const int LIMIT_FRAME = 5; + +namespace { +// DirectShow helper implementation +void _FreeMediaType(AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) { + CoTaskMemFree((PVOID)mt.pbFormat); + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) { + // pUnk should not be used. + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} + +} // end namespace + +class SampleGrabberCallbackPrivate : public ISampleGrabberCB +{ +public: + STDMETHODIMP_(ULONG) AddRef() { return 1; } + STDMETHODIMP_(ULONG) Release() { return 2; } + + STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) + { + if (NULL == ppvObject) + return E_POINTER; + if (riid == IID_IUnknown /*__uuidof(IUnknown) */ ) { + *ppvObject = static_cast<IUnknown*>(this); + return S_OK; + } + if (riid == IID_ISampleGrabberCB /*__uuidof(ISampleGrabberCB)*/ ) { + *ppvObject = static_cast<ISampleGrabberCB*>(this); + return S_OK; + } + return E_NOTIMPL; + } + + STDMETHODIMP SampleCB(double Time, IMediaSample *pSample) + { + return E_NOTIMPL; + } + + STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen) + { + if (!cs || active) { + return S_OK; + } + + if ((cs->StillMediaType.majortype != MEDIATYPE_Video) || + (cs->StillMediaType.formattype != FORMAT_VideoInfo) || + (cs->StillMediaType.cbFormat < sizeof(VIDEOINFOHEADER))) { + return VFW_E_INVALIDMEDIATYPE; + } + + active = true; + + if(toggle == true) { + toggle = false; + } + else { + toggle = true; + } + + if(toggle) { + active = false; + return S_OK; + } + + bool check = false; + cs->mutex.lock(); + + if (cs->frames.size() > LIMIT_FRAME) { + check = true; + } + + if (check) { + cs->mutex.unlock(); + // Frames building up. We're going to drop some here + Sleep(100); + active = false; + return S_OK; + } + cs->mutex.unlock(); + + unsigned char* vidData = new unsigned char[BufferLen]; + memcpy(vidData, pBuffer, BufferLen); + + cs->mutex.lock(); + + video_buffer* buf = new video_buffer; + buf->buffer = vidData; + buf->length = BufferLen; + buf->time = (qint64)Time; + + cs->frames.append(buf); + + cs->mutex.unlock(); + + QMetaObject::invokeMethod(cs, "captureFrame", Qt::QueuedConnection); + + active = false; + + return S_OK; + } + + DSCameraSession* cs; + bool active; + bool toggle; +}; + + +DSCameraSession::DSCameraSession(QObject *parent) + : QObject(parent) + ,m_currentImageId(0) +{ + pBuild = NULL; + pGraph = NULL; + pCap = NULL; + pSG_Filter = NULL; + pSG = NULL; + + opened = false; + available = false; + resolutions.clear(); + m_state = QCamera::UnloadedState; + m_device = "default"; + + StillCapCB = new SampleGrabberCallbackPrivate; + StillCapCB->cs = this; + StillCapCB->active = false; + StillCapCB->toggle = false; + + m_output = 0; + m_surface = 0; + m_windowSize = QSize(320,240); + pixelF = QVideoFrame::Format_RGB24; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + + graph = false; + active = false; + + ::CoInitialize(NULL); +} + +DSCameraSession::~DSCameraSession() +{ + if (opened) { + closeStream(); + } + + CoUninitialize(); + + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + + if (StillCapCB) { + delete StillCapCB; + } +} + +int DSCameraSession::captureImage(const QString &fileName) +{ + emit readyForCaptureChanged(false); + + // We're going to do this in one big synchronous call + m_currentImageId++; + if (fileName.isEmpty()) { + m_snapshot = "img.jpg"; + } else { + m_snapshot = fileName; + } + + if (!active) { + startStream(); + } + + return m_currentImageId; +} + +void DSCameraSession::setSurface(QAbstractVideoSurface* surface) +{ + m_surface = surface; +} + +bool DSCameraSession::deviceReady() +{ + return available; +} + +bool DSCameraSession::pictureInProgress() +{ + return m_snapshot.isEmpty(); +} + +int DSCameraSession::framerate() const +{ + return -1; +} + +void DSCameraSession::setFrameRate(int rate) +{ + Q_UNUSED(rate) +} + +int DSCameraSession::brightness() const +{ + return -1; +} + +void DSCameraSession::setBrightness(int b) +{ + Q_UNUSED(b) +} + +int DSCameraSession::contrast() const +{ + return -1; +} + +void DSCameraSession::setContrast(int c) +{ + Q_UNUSED(c) +} + +int DSCameraSession::saturation() const +{ + return -1; +} + +void DSCameraSession::setSaturation(int s) +{ + Q_UNUSED(s) +} + +int DSCameraSession::hue() const +{ + return -1; +} + +void DSCameraSession::setHue(int h) +{ + Q_UNUSED(h) +} + +int DSCameraSession::sharpness() const +{ + return -1; +} + +void DSCameraSession::setSharpness(int s) +{ + Q_UNUSED(s) +} + +int DSCameraSession::zoom() const +{ + return -1; +} + +void DSCameraSession::setZoom(int z) +{ + Q_UNUSED(z) +} + +bool DSCameraSession::backlightCompensation() const +{ + return false; +} + +void DSCameraSession::setBacklightCompensation(bool b) +{ + Q_UNUSED(b) +} + +int DSCameraSession::whitelevel() const +{ + return -1; +} + +void DSCameraSession::setWhitelevel(int w) +{ + Q_UNUSED(w) +} + +int DSCameraSession::rotation() const +{ + return 0; +} + +void DSCameraSession::setRotation(int r) +{ + Q_UNUSED(r) +} + +bool DSCameraSession::flash() const +{ + return false; +} + +void DSCameraSession::setFlash(bool f) +{ + Q_UNUSED(f) +} + +bool DSCameraSession::autofocus() const +{ + return false; +} + +void DSCameraSession::setAutofocus(bool f) +{ + Q_UNUSED(f) +} + +QSize DSCameraSession::frameSize() const +{ + return m_windowSize; +} + +void DSCameraSession::setFrameSize(const QSize& s) +{ + if (supportedResolutions(pixelF).contains(s)) + m_windowSize = s; + else + qWarning() << "frame size if not supported for current pixel format, no change"; +} + +void DSCameraSession::setDevice(const QString &device) +{ + if(opened) + stopStream(); + + if(graph) { + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + } + + available = false; + m_state = QCamera::LoadedState; + + CoInitialize(NULL); + + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast<void**>(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (S_OK == hr) { + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"Description", &varName, 0); + if(FAILED(hr)) + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp(QString::fromUtf16((unsigned short*)str)); + if(temp.contains(device)) { + available = true; + } + } + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } + CoUninitialize(); + + if(available) { + m_device = QByteArray(device.toLocal8Bit().constData()); + graph = createFilterGraph(); + if(!graph) + available = false; + } +} + +QList<QVideoFrame::PixelFormat> DSCameraSession::supportedPixelFormats() +{ + return types; +} + +QVideoFrame::PixelFormat DSCameraSession::pixelFormat() const +{ + return pixelF; +} + +void DSCameraSession::setPixelFormat(QVideoFrame::PixelFormat fmt) +{ + pixelF = fmt; +} + +QList<QSize> DSCameraSession::supportedResolutions(QVideoFrame::PixelFormat format) +{ + if (!resolutions.contains(format)) + return QList<QSize>(); + return resolutions.value(format); +} + +bool DSCameraSession::setOutputLocation(const QUrl &sink) +{ + m_sink = sink; + + return true; +} + +QUrl DSCameraSession::outputLocation() const +{ + return m_sink; +} + +qint64 DSCameraSession::position() const +{ + return timeStamp.elapsed(); +} + +int DSCameraSession::state() const +{ + return int(m_state); +} + +void DSCameraSession::record() +{ + if(opened) { + return; + } + + if(m_surface) { + bool match = false; + + if (!m_surface->isFormatSupported(actualFormat)) { + QList<QVideoFrame::PixelFormat> fmts; + foreach(QVideoFrame::PixelFormat f, types) { + if (fmts.contains(f)) { + match = true; + pixelF = f; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + break; + } + } + } + if (!m_surface->isFormatSupported(actualFormat) && !match) { + // fallback + if (types.contains(QVideoFrame::Format_RGB24)) { + // get RGB24 from camera and convert to RGB32 for surface! + pixelF = QVideoFrame::Format_RGB32; + actualFormat = QVideoSurfaceFormat(m_windowSize,pixelF); + } + } + + if (m_surface->isFormatSupported(actualFormat)) { + m_surface->start(actualFormat); + m_state = QCamera::ActiveState; + emit stateChanged(QCamera::ActiveState); + } else { + qWarning() << "surface doesn't support camera format, cant start"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + return; + } + } else { + qWarning() << "no video surface, cant start"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + return; + } + + opened = startStream(); + + if (!opened) { + qWarning() << "Stream did not open"; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); + } +} + +void DSCameraSession::pause() +{ + suspendStream(); +} + +void DSCameraSession::stop() +{ + if(!opened) { + return; + } + + stopStream(); + opened = false; + m_state = QCamera::LoadedState; + emit stateChanged(QCamera::LoadedState); +} + +void DSCameraSession::captureFrame() +{ + if(m_surface && frames.count() > 0) { + + QImage image; + + if(pixelF == QVideoFrame::Format_RGB24) { + + mutex.lock(); + + image = QImage(frames.at(0)->buffer,m_windowSize.width(),m_windowSize.height(), + QImage::Format_RGB888).rgbSwapped().mirrored(true); + + QVideoFrame frame(image); + frame.setStartTime(frames.at(0)->time); + + mutex.unlock(); + + m_surface->present(frame); + + } else if (pixelF == QVideoFrame::Format_RGB32) { + + mutex.lock(); + + image = QImage(frames.at(0)->buffer,m_windowSize.width(),m_windowSize.height(), + QImage::Format_RGB888).rgbSwapped().mirrored(true); + + QVideoFrame frame(image.convertToFormat(QImage::Format_RGB32)); + frame.setStartTime(frames.at(0)->time); + + mutex.unlock(); + + m_surface->present(frame); + + } else { + qWarning() << "TODO:captureFrame() format =" << pixelF; + } + + if (m_snapshot.length() > 0) { + emit imageCaptured(m_currentImageId, image); + image.save(m_snapshot,"JPG"); + emit imageSaved(m_currentImageId, m_snapshot); + m_snapshot.clear(); + emit readyForCaptureChanged(true); + } + + mutex.lock(); + if (frames.isEmpty()) { + qWarning() << "Frames over-run"; + } + + video_buffer* buf = frames.takeFirst(); + delete buf->buffer; + delete buf; + mutex.unlock(); + } +} + +HRESULT DSCameraSession::getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin) +{ + *ppPin = 0; + IEnumPins *pEnum = 0; + IPin *pPin = 0; + + HRESULT hr = pFilter->EnumPins(&pEnum); + if(FAILED(hr)) { + return hr; + } + + pEnum->Reset(); + while(pEnum->Next(1, &pPin, NULL) == S_OK) { + PIN_DIRECTION ThisPinDir; + pPin->QueryDirection(&ThisPinDir); + if(ThisPinDir == PinDir) { + pEnum->Release(); + *ppPin = pPin; + return S_OK; + } + pEnum->Release(); + } + pEnum->Release(); + return E_FAIL; +} + +bool DSCameraSession::createFilterGraph() +{ + HRESULT hr; + IMoniker* pMoniker = NULL; + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + + CoInitialize(NULL); + + // Create the filter graph + hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC, + IID_IGraphBuilder, (void**)&pGraph); + if (FAILED(hr)) { + qWarning()<<"failed to create filter graph"; + return false; + } + + // Create the capture graph builder + hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, + IID_ICaptureGraphBuilder2, (void**)&pBuild); + if (FAILED(hr)) { + qWarning()<<"failed to create graph builder"; + return false; + } + + // Attach the filter graph to the capture graph + hr = pBuild->SetFiltergraph(pGraph); + if (FAILED(hr)) { + qWarning()<<"failed to connect capture graph and filter graph"; + return false; + } + + // Find the Capture device + hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast<void**>(&pDevEnum)); + if (SUCCEEDED(hr)) { + // Create an enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnum, 0); + pDevEnum->Release(); + if (S_OK == hr) { + pEnum->Reset(); + //go through and find all video capture devices + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, + IID_IPropertyBag, (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)) { + // check if it is the selected device + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString output = QString::fromUtf16((unsigned short*)str); + if (m_device.contains(output.toLocal8Bit().constData())) { + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); + if (SUCCEEDED(hr)) { + pPropBag->Release(); + pMoniker->Release(); + break; + } + } + } + pPropBag->Release(); + pMoniker->Release(); + } + if (NULL == pCap) + { + if (m_device.contains("default")) + { + pEnum->Reset(); + // still have to loop to discard bind to storage failure case + while (pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag = 0; + + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)(&pPropBag)); + if (FAILED(hr)) { + pMoniker->Release(); + continue; // Don't panic yet + } + + // No need to get the description, just grab it + + hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCap); + pPropBag->Release(); + pMoniker->Release(); + if (SUCCEEDED(hr)) { + break; // done, stop looping through + } + else + { + qWarning() << "Object bind failed"; + } + } + } + } + pEnum->Release(); + } + } + + // Sample grabber filter + hr = CoCreateInstance(CLSID_SampleGrabber, NULL,CLSCTX_INPROC, + IID_IBaseFilter, (void**)&pSG_Filter); + if (FAILED(hr)) { + qWarning() << "failed to create sample grabber"; + return false; + } + + pSG_Filter->QueryInterface(IID_ISampleGrabber, (void**)&pSG); + if (FAILED(hr)) { + qWarning() << "failed to get sample grabber"; + return false; + } + pSG->SetOneShot(FALSE); + pSG->SetBufferSamples(TRUE); + pSG->SetCallback(StillCapCB, 1); + + CoUninitialize(); + + return true; +} + +void DSCameraSession::updateProperties() +{ + HRESULT hr; + AM_MEDIA_TYPE *pmt = NULL; + VIDEOINFOHEADER *pvi = NULL; + VIDEO_STREAM_CONFIG_CAPS scc; + IAMStreamConfig* pConfig = 0; + + hr = pBuild->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video,pCap, + IID_IAMStreamConfig, (void**)&pConfig); + if (FAILED(hr)) { + qWarning()<<"failed to get config on capture device"; + return; + } + + int iCount; + int iSize; + hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); + if (FAILED(hr)) { + qWarning()<<"failed to get capabilities"; + return; + } + + QList<QSize> sizes; + QVideoFrame::PixelFormat f = QVideoFrame::Format_Invalid; + + types.clear(); + resolutions.clear(); + + for (int iIndex = 0; iIndex < iCount; iIndex++) { + hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast<BYTE*>(&scc)); + if (hr == S_OK) { + pvi = (VIDEOINFOHEADER*)pmt->pbFormat; + if ((pmt->majortype == MEDIATYPE_Video) && + (pmt->formattype == FORMAT_VideoInfo)) { + // Add types + if (pmt->subtype == MEDIASUBTYPE_RGB24) { + if (!types.contains(QVideoFrame::Format_RGB24)) { + types.append(QVideoFrame::Format_RGB24); + f = QVideoFrame::Format_RGB24; + } + } else if (pmt->subtype == MEDIASUBTYPE_RGB32) { + if (!types.contains(QVideoFrame::Format_RGB32)) { + types.append(QVideoFrame::Format_RGB32); + f = QVideoFrame::Format_RGB32; + } + } else if (pmt->subtype == MEDIASUBTYPE_YUY2) { + if (!types.contains(QVideoFrame::Format_YUYV)) { + types.append(QVideoFrame::Format_YUYV); + f = QVideoFrame::Format_YUYV; + } + } else if (pmt->subtype == MEDIASUBTYPE_MJPG) { + } else if (pmt->subtype == MEDIASUBTYPE_I420) { + if (!types.contains(QVideoFrame::Format_YUV420P)) { + types.append(QVideoFrame::Format_YUV420P); + f = QVideoFrame::Format_YUV420P; + } + } else if (pmt->subtype == MEDIASUBTYPE_RGB555) { + if (!types.contains(QVideoFrame::Format_RGB555)) { + types.append(QVideoFrame::Format_RGB555); + f = QVideoFrame::Format_RGB555; + } + } else if (pmt->subtype == MEDIASUBTYPE_YVU9) { + } else if (pmt->subtype == MEDIASUBTYPE_UYVY) { + if (!types.contains(QVideoFrame::Format_UYVY)) { + types.append(QVideoFrame::Format_UYVY); + f = QVideoFrame::Format_UYVY; + } + } else { + qWarning() << "UNKNOWN FORMAT: " << pmt->subtype.Data1; + } + // Add resolutions + QSize res(pvi->bmiHeader.biWidth, pvi->bmiHeader.biHeight); + if (!resolutions.contains(f)) { + sizes.clear(); + resolutions.insert(f,sizes); + } + resolutions[f].append(res); + } + } + } + pConfig->Release(); +} + +bool DSCameraSession::setProperties() +{ + CoInitialize(NULL); + + HRESULT hr; + AM_MEDIA_TYPE am_media_type; + AM_MEDIA_TYPE *pmt = NULL; + VIDEOINFOHEADER *pvi = NULL; + VIDEO_STREAM_CONFIG_CAPS scc; + + IAMStreamConfig* pConfig = 0; + hr = pBuild->FindInterface(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, pCap, + IID_IAMStreamConfig, (void**)&pConfig); + if(FAILED(hr)) { + qWarning()<<"failed to get config on capture device"; + return false; + } + + int iCount; + int iSize; + hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize); + if(FAILED(hr)) { + qWarning()<<"failed to get capabilities"; + return false; + } + + bool setFormatOK = false; + for (int iIndex = 0; iIndex < iCount; iIndex++) { + hr = pConfig->GetStreamCaps(iIndex, &pmt, reinterpret_cast<BYTE*>(&scc)); + if (hr == S_OK) { + pvi = (VIDEOINFOHEADER*)pmt->pbFormat; + + if ((pmt->majortype == MEDIATYPE_Video) && + (pmt->formattype == FORMAT_VideoInfo)) { + if ((actualFormat.frameWidth() == pvi->bmiHeader.biWidth) && + (actualFormat.frameHeight() == pvi->bmiHeader.biHeight)) { + hr = pConfig->SetFormat(pmt); + _FreeMediaType(*pmt); + if(FAILED(hr)) { + qWarning()<<"failed to set format:" << hr; + qWarning()<<"but going to continue"; + continue; // We going to continue + } else { + setFormatOK = true; + break; + } + } + } + } + } + pConfig->Release(); + + if (!setFormatOK) { + qWarning() << "unable to set any format for camera"; + return false; + } + + // Set Sample Grabber config to match capture + ZeroMemory(&am_media_type, sizeof(am_media_type)); + am_media_type.majortype = MEDIATYPE_Video; + + if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB32) + am_media_type.subtype = MEDIASUBTYPE_RGB24; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB24) + am_media_type.subtype = MEDIASUBTYPE_RGB24; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_YUYV) + am_media_type.subtype = MEDIASUBTYPE_YUY2; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_YUV420P) + am_media_type.subtype = MEDIASUBTYPE_I420; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_RGB555) + am_media_type.subtype = MEDIASUBTYPE_RGB555; + else if (actualFormat.pixelFormat() == QVideoFrame::Format_UYVY) + am_media_type.subtype = MEDIASUBTYPE_UYVY; + else { + qWarning()<<"unknown format? for SG"; + return false; + } + + am_media_type.formattype = FORMAT_VideoInfo; + hr = pSG->SetMediaType(&am_media_type); + if (FAILED(hr)) { + qWarning()<<"failed to set video format on grabber"; + return false; + } + + pSG->GetConnectedMediaType(&StillMediaType); + + CoUninitialize(); + + return true; +} + +bool DSCameraSession::openStream() +{ + //Opens the stream for reading and allocates any necessary resources needed + //Return true if success, false otherwise + + if (opened) { + return true; + } + + if (!graph) { + graph = createFilterGraph(); + if(!graph) { + qWarning()<<"failed to create filter graph in openStream"; + return false; + } + } + + CoInitialize(NULL); + + HRESULT hr; + + hr = pGraph->AddFilter(pCap, L"Capture Filter"); + if (FAILED(hr)) { + qWarning()<<"failed to create capture filter"; + return false; + } + + hr = pGraph->AddFilter(pSG_Filter, L"Sample Grabber"); + if (FAILED(hr)) { + qWarning()<<"failed to add sample grabber"; + return false; + } + + hr = pBuild->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, + pCap, NULL, pSG_Filter); + if (FAILED(hr)) { + qWarning() << "failed to renderstream" << hr; + return false; + } + pSG->GetConnectedMediaType(&StillMediaType); + pSG_Filter->Release(); + + CoUninitialize(); + + return true; +} + +void DSCameraSession::closeStream() +{ + // Closes the stream and internally frees any resources used + HRESULT hr; + IMediaControl* pControl = 0; + + hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl); + if (FAILED(hr)) { + qWarning()<<"failed to get stream control"; + return; + } + + hr = pControl->StopWhenReady(); + if (FAILED(hr)) { + qWarning()<<"failed to stop"; + pControl->Release(); + return; + } + + pControl->Release(); + + opened = false; + IPin *pPin = 0; + + if (pCap) + { + hr = getPin(pCap, PINDIR_OUTPUT, &pPin); + if(FAILED(hr)) { + qWarning()<<"failed to disconnect capture filter"; + return; + } + } + + pGraph->Disconnect(pPin); + if (FAILED(hr)) { + qWarning()<<"failed to disconnect grabber filter"; + return; + } + + hr = getPin(pSG_Filter,PINDIR_INPUT,&pPin); + pGraph->Disconnect(pPin); + pGraph->RemoveFilter(pSG_Filter); + pGraph->RemoveFilter(pCap); + + SAFE_RELEASE(pCap); + SAFE_RELEASE(pSG_Filter); + SAFE_RELEASE(pGraph); + SAFE_RELEASE(pBuild); + + graph = false; +} + +bool DSCameraSession::startStream() +{ + // Starts the stream, by emitting either QVideoPackets + // or QvideoFrames, depending on Format chosen + if (!graph) + graph = createFilterGraph(); + + if (!setProperties()) { + qWarning() << "Couldn't set properties (retrying)"; + closeStream(); + if (!openStream()) { + qWarning() << "Retry to open strean failed"; + return false; + } + } + + if (!opened) { + opened = openStream(); + if (!opened) { + qWarning() << "failed to openStream()"; + return false; + } + } + + HRESULT hr; + IMediaControl* pControl = 0; + + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return false; + } + + hr = pControl->Run(); + pControl->Release(); + + if (FAILED(hr)) { + qWarning() << "failed to start"; + return false; + } + active = true; + return true; +} + +void DSCameraSession::stopStream() +{ + // Stops the stream from emitting packets + HRESULT hr; + + IMediaControl* pControl = 0; + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return; + } + + hr = pControl->Stop(); + pControl->Release(); + if (FAILED(hr)) { + qWarning() << "failed to stop"; + return; + } + active = false; + + if (opened) { + closeStream(); + } +} + +void DSCameraSession::suspendStream() +{ + // Pauses the stream + HRESULT hr; + + IMediaControl* pControl = 0; + hr = pGraph->QueryInterface(IID_IMediaControl, (void**)&pControl); + if (FAILED(hr)) { + qWarning() << "failed to get stream control"; + return; + } + + hr = pControl->Pause(); + pControl->Release(); + if (FAILED(hr)) { + qWarning() << "failed to pause"; + return; + } + + active = false; +} + +void DSCameraSession::resumeStream() +{ + // Resumes a paused stream + startStream(); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h new file mode 100644 index 000000000..72a0e5077 --- /dev/null +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSCAMERASESSION_H +#define DSCAMERASESSION_H + +#include <QtCore/qobject.h> +#include <QTime> +#include <QUrl> +#include <QMutex> + +#include <qcamera.h> +#include <QtMultimedia/qvideoframe.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#include <tchar.h> +#include <dshow.h> +#include <objbase.h> +#include <initguid.h> +#pragma comment(lib, "strmiids.lib") +#pragma comment(lib, "ole32.lib") +#include <windows.h> + +#pragma include_alias("dxtrans.h","qedit.h") +#define __IDxtCompositor_INTERFACE_DEFINED__ +#define __IDxtAlphaSetter_INTERFACE_DEFINED__ +#define __IDxtJpeg_INTERFACE_DEFINED__ +#define __IDxtKey_INTERFACE_DEFINED__ +#include <qedit.h> + +struct ICaptureGraphBuilder2; +struct ISampleGrabber; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSVideoRenderer; +class SampleGrabberCallbackPrivate; + + +struct video_buffer { + unsigned char* buffer; + int length; + qint64 time; +}; + +typedef QMap<unsigned int, QList<QSize> > FormatResolutionMap; + +class DSCameraSession : public QObject +{ + Q_OBJECT +public: + DSCameraSession(QObject *parent = 0); + ~DSCameraSession(); + + bool deviceReady(); + bool pictureInProgress(); + + // camera controls + + int framerate() const; + void setFrameRate(int rate); + int brightness() const; + void setBrightness(int b); + int contrast() const; + void setContrast(int c); + int saturation() const; + void setSaturation(int s); + int hue() const; + void setHue(int h); + int sharpness() const; + void setSharpness(int s); + int zoom() const; + void setZoom(int z); + bool backlightCompensation() const; + void setBacklightCompensation(bool); + int whitelevel() const; + void setWhitelevel(int w); + int rotation() const; + void setRotation(int r); + bool flash() const; + void setFlash(bool f); + bool autofocus() const; + void setAutofocus(bool f); + + QSize frameSize() const; + void setFrameSize(const QSize& s); + void setDevice(const QString &device); + QList<QVideoFrame::PixelFormat> supportedPixelFormats(); + QVideoFrame::PixelFormat pixelFormat() const; + void setPixelFormat(QVideoFrame::PixelFormat fmt); + QList<QSize> supportedResolutions(QVideoFrame::PixelFormat format); + + // media control + + bool setOutputLocation(const QUrl &sink); + QUrl outputLocation() const; + qint64 position() const; + int state() const; + void record(); + void pause(); + void stop(); + + void setSurface(QAbstractVideoSurface* surface); + + int captureImage(const QString &fileName); + + AM_MEDIA_TYPE StillMediaType; + QList<video_buffer*> frames; + SampleGrabberCallbackPrivate* StillCapCB; + + QMutex mutex; + +Q_SIGNALS: + void stateChanged(QCamera::State); + void imageCaptured(int id, const QImage &preview); + void imageSaved(int id, const QString &fileName); + void readyForCaptureChanged(bool); + +private Q_SLOTS: + void captureFrame(); + +private: + QVideoSurfaceFormat actualFormat; + QList<QVideoFrame::PixelFormat> types; + + QTime timeStamp; + bool graph; + bool active; + bool opened; + bool available; + QCamera::State m_state; + QByteArray m_device; + QUrl m_sink; + DSVideoRenderer* m_output; + QAbstractVideoSurface* m_surface; + QVideoFrame::PixelFormat pixelF; + QSize m_windowSize; + FormatResolutionMap resolutions; + + ICaptureGraphBuilder2* pBuild; + IGraphBuilder* pGraph; + IBaseFilter* pCap; + IBaseFilter* pSG_Filter; + ISampleGrabber *pSG; + + + QString m_snapshot; + int m_currentImageId; +protected: + HRESULT getPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin **ppPin); + bool createFilterGraph(); + void updateProperties(); + bool setProperties(); + bool openStream(); + void closeStream(); + bool startStream(); + void stopStream(); + void suspendStream(); + void resumeStream(); +}; + +QT_END_NAMESPACE + +QT_END_HEADER + + +#endif diff --git a/src/plugins/directshow/camera/dsimagecapturecontrol.cpp b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp new file mode 100644 index 000000000..17654c4a5 --- /dev/null +++ b/src/plugins/directshow/camera/dsimagecapturecontrol.cpp @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QtCore/QDebug> + +#include "dsimagecapturecontrol.h" + +QT_BEGIN_NAMESPACE + +DSImageCaptureControl::DSImageCaptureControl(DSCameraSession *session) + :QCameraImageCaptureControl(session), m_session(session), m_ready(false) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(updateState())); + connect(m_session, SIGNAL(imageCaptured(const int, QImage)), + this, SIGNAL(imageCaptured(const int, QImage))); + connect(m_session, SIGNAL(imageSaved(const int, const QString &)), + this, SIGNAL(imageSaved(const int, const QString &))); + connect(m_session, SIGNAL(readyForCaptureChanged(bool)), + this, SIGNAL(readyForCaptureChanged(bool))); +} + +DSImageCaptureControl::~DSImageCaptureControl() +{ +} + +bool DSImageCaptureControl::isReadyForCapture() const +{ + return m_ready; +} + +int DSImageCaptureControl::capture(const QString &fileName) +{ + return m_session->captureImage(fileName); +} + +void DSImageCaptureControl::updateState() +{ + bool ready = (m_session->state() == QCamera::ActiveState) && + !m_session->pictureInProgress(); + if(m_ready != ready) + emit readyForCaptureChanged(m_ready = ready); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dsimagecapturecontrol.h b/src/plugins/directshow/camera/dsimagecapturecontrol.h new file mode 100644 index 000000000..8eca7b4e7 --- /dev/null +++ b/src/plugins/directshow/camera/dsimagecapturecontrol.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSIMAGECAPTURECONTROL_H +#define DSIMAGECAPTURECONTROL_H + +#include <qcameraimagecapturecontrol.h> +#include "dscamerasession.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSImageCaptureControl : public QCameraImageCaptureControl +{ + Q_OBJECT +public: + DSImageCaptureControl(DSCameraSession *session); + virtual ~DSImageCaptureControl(); + + bool isReadyForCapture() const; + int capture(const QString &fileName); + + virtual QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } + virtual void setDriveMode(QCameraImageCapture::DriveMode mode) { } + + virtual void cancelCapture() {} + +private slots: + void updateState(); + + +private: + DSCameraSession *m_session; + bool m_ready; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSCAPTURECONTROL_H diff --git a/src/plugins/directshow/camera/dsvideodevicecontrol.cpp b/src/plugins/directshow/camera/dsvideodevicecontrol.cpp new file mode 100644 index 000000000..8c9b03000 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideodevicecontrol.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QDebug> +#include <QFile> +#include <QtGui/QIcon> + +#include "dsvideodevicecontrol.h" +#include "dscamerasession.h" + +#include <tchar.h> +#include <dshow.h> +#include <objbase.h> +#include <initguid.h> +#include <Ocidl.h> +#include <string.h> + +extern const CLSID CLSID_VideoInputDeviceCategory; + +QT_BEGIN_NAMESPACE + +DSVideoDeviceControl::DSVideoDeviceControl(QObject *parent) + : QVideoDeviceControl(parent) +{ + m_session = qobject_cast<DSCameraSession*>(parent); + + devices.clear(); + descriptions.clear(); + + CoInitialize(NULL); + ICreateDevEnum* pDevEnum = NULL; + IEnumMoniker* pEnum = NULL; + // Create the System device enumerator + HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, + CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, + reinterpret_cast<void**>(&pDevEnum)); + if(SUCCEEDED(hr)) { + // Create the enumerator for the video capture category + hr = pDevEnum->CreateClassEnumerator( + CLSID_VideoInputDeviceCategory, &pEnum, 0); + if (S_OK == hr) { + pEnum->Reset(); + // go through and find all video capture devices + IMoniker* pMoniker = NULL; + while(pEnum->Next(1, &pMoniker, NULL) == S_OK) { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void**)(&pPropBag)); + if(FAILED(hr)) { + pMoniker->Release(); + continue; // skip this one + } + // Find the description + WCHAR str[120]; + VARIANT varName; + varName.vt = VT_BSTR; + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if(SUCCEEDED(hr)) { + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp(QString::fromUtf16((unsigned short*)str)); + devices.append(QString("ds:%1").arg(temp).toLocal8Bit().constData()); + hr = pPropBag->Read(L"Description", &varName, 0); + wcsncpy(str, varName.bstrVal, sizeof(str)/sizeof(str[0])); + QString temp2(QString::fromUtf16((unsigned short*)str)); + descriptions.append(temp2.toLocal8Bit().constData()); + } + pPropBag->Release(); + pMoniker->Release(); + } + pEnum->Release(); + } + pDevEnum->Release(); + } + CoUninitialize(); + + selected = 0; +} + +int DSVideoDeviceControl::deviceCount() const +{ + return devices.count(); +} + +QString DSVideoDeviceControl::deviceName(int index) const +{ + if(index >= 0 && index <= devices.count()) + return devices.at(index); + + return QString(); +} + +QString DSVideoDeviceControl::deviceDescription(int index) const +{ + if(index >= 0 && index <= descriptions.count()) + return descriptions.at(index); + + return QString(); +} + +QIcon DSVideoDeviceControl::deviceIcon(int index) const +{ + Q_UNUSED(index) + + return QIcon(); +} + +int DSVideoDeviceControl::defaultDevice() const +{ + return 0; +} + +int DSVideoDeviceControl::selectedDevice() const +{ + return selected; +} + +void DSVideoDeviceControl::setSelectedDevice(int index) +{ + if(index >= 0 && index <= devices.count()) { + if (m_session) { + QString device = devices.at(index); + if (device.startsWith("ds:")) + device.remove(0,3); + m_session->setDevice(device); + } + selected = index; + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dsvideodevicecontrol.h b/src/plugins/directshow/camera/dsvideodevicecontrol.h new file mode 100644 index 000000000..8391c4eda --- /dev/null +++ b/src/plugins/directshow/camera/dsvideodevicecontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSVIDEODEVICECONTROL_H +#define DSVIDEODEVICECONTROL_H + +#include <qvideodevicecontrol.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE +class DSCameraSession; + +//QTM_USE_NAMESPACE + +class DSVideoDeviceControl : public QVideoDeviceControl +{ + Q_OBJECT +public: + DSVideoDeviceControl(QObject *parent = 0); + + int deviceCount() const; + QString deviceName(int index) const; + QString deviceDescription(int index) const; + QIcon deviceIcon(int index) const; + int defaultDevice() const; + int selectedDevice() const; + +public Q_SLOTS: + void setSelectedDevice(int index); + +private: + DSCameraSession* m_session; + + QList<QString> devices; + QList<QString> descriptions; + + int selected; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/plugins/directshow/camera/dsvideorenderer.cpp b/src/plugins/directshow/camera/dsvideorenderer.cpp new file mode 100644 index 000000000..0fbdb15b1 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideorenderer.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 <QtCore/qdebug.h> + +#include "dsvideorenderer.h" + +QT_BEGIN_NAMESPACE + +DSVideoRendererControl::DSVideoRendererControl(DSCameraSession* session, QObject *parent) + :QVideoRendererControl(parent), + m_surface(0), + m_session(session) +{ +} + +DSVideoRendererControl::~DSVideoRendererControl() +{ +} + +QAbstractVideoSurface* DSVideoRendererControl::surface() const +{ + return m_surface; +} + +void DSVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + m_surface = surface; + if(m_session) + m_session->setSurface(m_surface); +} + +QT_END_NAMESPACE + diff --git a/src/plugins/directshow/camera/dsvideorenderer.h b/src/plugins/directshow/camera/dsvideorenderer.h new file mode 100644 index 000000000..b941504ac --- /dev/null +++ b/src/plugins/directshow/camera/dsvideorenderer.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the 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 DSVIDEORENDERER_H +#define DSVIDEORENDERER_H + +#include <qvideorenderercontrol.h> +#include "dscamerasession.h" + +class CameraFormatConverter; + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + + +class DSVideoRendererControl : public QVideoRendererControl +{ + Q_OBJECT +public: + DSVideoRendererControl(DSCameraSession* session, QObject *parent = 0); + ~DSVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void setSession(DSCameraSession* session); + +private: + QAbstractVideoSurface* m_surface; + DSCameraSession* m_session; + CameraFormatConverter* converter; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSVIDEORENDERER_H diff --git a/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp b/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp new file mode 100644 index 000000000..8298c0275 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideowidgetcontrol.cpp @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** 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 <QtCore/qcoreevent.h> +#include <QtCore/qtimer.h> + +#include "DSVideoWidgetControl.h" +#include "dscamerasession.h" + +QT_BEGIN_NAMESPACE + +DSVideoWidgetSurface::DSVideoWidgetSurface(QLabel *pWidget, QObject *parent) +{ + widget = pWidget; + myPixmap = 0; +} + +QList<QVideoFrame::PixelFormat> DSVideoWidgetSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + if (handleType == QAbstractVideoBuffer::NoHandle) { + return QList<QVideoFrame::PixelFormat>() + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_RGB24; + } else { + return QList<QVideoFrame::PixelFormat>(); + } +} + + +bool DSVideoWidgetSurface::present(const QVideoFrame &frame) +{ + QVideoFrame myFrame = frame; + myFrame.map(QAbstractVideoBuffer::ReadOnly); + QImage image( + frame.bits(), + frame.width(), + frame.height(), + frame.bytesPerLine(), + imageFormat); + if (image.isNull()) + { + // Try to adapt + QImage image2( + frame.bits(), + frame.width(), + frame.height(), + frame.bytesPerLine(), + QImage::Format_RGB888); + image = image2; + } + myFrame.unmap(); + delete myPixmap; + myPixmap = new QPixmap(QPixmap::fromImage(image).scaled(widget->size())); + widget->setPixmap(*myPixmap); + widget->repaint(); + return true; +} + +void DSVideoWidgetSurface::setImageFormat(QImage::Format fmt) +{ + imageFormat = fmt; +} + +void DSVideoWidgetSurface::updateVideoRect() +{ +} + +void DSVideoWidgetSurface::paint(QPainter *painter) +{ +} + + +DSVideoWidgetControl::DSVideoWidgetControl(DSCameraSession* session, QObject *parent) : + m_session(session), QVideoWidgetControl(parent), + m_widget(new QLabel()), + m_fullScreen(false) +{ + m_widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_widget->setAlignment(Qt::AlignCenter); + m_widget->setAttribute(Qt::WA_NoSystemBackground, true); + + surface = new DSVideoWidgetSurface(m_widget); + + QPalette palette; + palette.setColor(QPalette::Background, Qt::black); + m_widget->setPalette(palette); + m_widget->setAutoFillBackground( true ); + + // Request QEvents + m_widget->installEventFilter(this); + m_windowId = m_widget->effectiveWinId(); + + surface->setImageFormat(QImage::Format_RGB888); + session->setSurface(surface); +} + +DSVideoWidgetControl::~DSVideoWidgetControl() +{ + delete m_widget; +} + +bool DSVideoWidgetControl::eventFilter(QObject *object, QEvent *e) +{ + if (object == m_widget) { + switch (e->type()) { + case QEvent::ParentChange: + case QEvent::WinIdChange: + case QEvent::Show: + m_windowId = m_widget->effectiveWinId(); + emit widgetUpdated(); + break; + case QEvent::Resize: + emit widgetResized(m_widget->size()); + break; + case QEvent::PolishRequest: + m_widget->ensurePolished(); + break; + + default: + // Do nothing + break; + } + } + return false; +} + +QWidget *DSVideoWidgetControl::videoWidget() +{ + return m_widget; +} + +Qt::AspectRatioMode DSVideoWidgetControl::aspectRatioMode() const +{ + return m_aspectRatioMode; +} + +void DSVideoWidgetControl::setAspectRatioMode(Qt::AspectRatioMode ratio) +{ + if (m_aspectRatioMode==ratio) { + return; + } + m_aspectRatioMode = ratio; + + if (m_aspectRatioMode == Qt::KeepAspectRatio) + m_widget->setScaledContents(false); + else { + m_widget->setScaledContents(true); + } +} + +bool DSVideoWidgetControl::isFullScreen() const +{ + return m_fullScreen; +} + +void DSVideoWidgetControl::setFullScreen(bool fullScreen) +{ + if (m_widget && !fullScreen && m_fullScreen) { + m_widget->showNormal(); + m_fullScreen = false; + } else if (m_widget && fullScreen) { + m_widget->showFullScreen(); + m_fullScreen = true; + } + + emit fullScreenChanged(fullScreen); +} + +int DSVideoWidgetControl::brightness() const +{ + return 0; +} + +void DSVideoWidgetControl::setBrightness(int brightness) +{ + Q_UNUSED(brightness); +} + +int DSVideoWidgetControl::contrast() const +{ + return 0; +} + +void DSVideoWidgetControl::setContrast(int contrast) +{ + Q_UNUSED(contrast); +} + +int DSVideoWidgetControl::hue() const +{ + return 0; +} + +void DSVideoWidgetControl::setHue(int hue) +{ + Q_UNUSED(hue); +} + +int DSVideoWidgetControl::saturation() const +{ + return 0; +} + +void DSVideoWidgetControl::setSaturation(int saturation) +{ + Q_UNUSED(saturation); +} + +QT_END_NAMESPACE + +// End of file diff --git a/src/plugins/directshow/camera/dsvideowidgetcontrol.h b/src/plugins/directshow/camera/dsvideowidgetcontrol.h new file mode 100644 index 000000000..e17827453 --- /dev/null +++ b/src/plugins/directshow/camera/dsvideowidgetcontrol.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** 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 DSVIDEOWIDGETCONTROL_H +#define DSVIDEOWIDGETCONTROL_H + +#include <QtCore/qobject.h> +#include <QtGui> +#include <QtMultimedia/qvideoframe.h> +#include <QtMultimedia/qabstractvideosurface.h> +#include <QtMultimedia/qvideosurfaceformat.h> + +#include <qvideowidgetcontrol.h> +#include "DsCameraControl.h" + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +class DSVideoWidgetSurface : public QAbstractVideoSurface +{ + Q_OBJECT + public: + DSVideoWidgetSurface(QLabel *pWidget, QObject *parent = 0); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const; + + bool present(const QVideoFrame &frame); + + QRect videoRect() const { return targetRect; } + void updateVideoRect(); + + void paint(QPainter *painter); + void setImageFormat(QImage::Format fmt); + + private: + QLabel *widget; + QImage::Format imageFormat; + QRect targetRect; + QSize imageSize; + QRect sourceRect; + QPixmap* myPixmap; + }; + +class DSVideoWidgetControl : public QVideoWidgetControl +{ + Q_OBJECT + + DSVideoWidgetSurface* surface; +public: // Constructor & Destructor + + DSVideoWidgetControl(DSCameraSession* session, QObject *parent = 0); + virtual ~DSVideoWidgetControl(); + +public: // QVideoWidgetControl + + QWidget *videoWidget(); + + // Aspect Ratio + Qt::AspectRatioMode aspectRatioMode() const; + void setAspectRatioMode(Qt::AspectRatioMode ratio); + + // Full Screen + bool isFullScreen() const; + void setFullScreen(bool fullScreen); + + // Brightness + int brightness() const; + void setBrightness(int brightness); + + // Contrast + int contrast() const; + void setContrast(int contrast); + + // Hue + int hue() const; + void setHue(int hue); + + // Saturation + int saturation() const; + void setSaturation(int saturation); + +public: // Internal + + bool eventFilter(QObject *object, QEvent *event); + +/* +Q_SIGNALS: // QVideoWidgetControl + + void fullScreenChanged(bool fullScreen); + void brightnessChanged(int brightness); + void contrastChanged(int contrast); + void hueChanged(int hue); + void saturationChanged(int saturation); +*/ + +Q_SIGNALS: // Internal Signals + + void widgetResized(QSize size); + void widgetUpdated(); + +private: // Data + + DSCameraSession* m_session; + QLabel *m_widget; + WId m_windowId; + Qt::AspectRatioMode m_aspectRatioMode; + bool m_fullScreen; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // DSVideoWidgetControl_H |