diff --git a/linphone/mediastreamer2/plugins/msdscap/comptr.hh b/linphone/mediastreamer2/plugins/msdscap/comptr.hh new file mode 100644 index 0000000000000000000000000000000000000000..6bfa0109e9071b85f468246702dba247f1a3f3b8 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/comptr.hh @@ -0,0 +1,73 @@ +/* HornetsEye - Computer Vision with Ruby + Copyright (C) 2006, 2007 Jan Wedekind + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef HORNETSEYE_COMPTR_HH +#define HORNETSEYE_COMPTR_HH + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef WIN32 +#include <cassert> +#include <objbase.h> +#include "error.hh" + +namespace Hornetseye { + + template< class I > + class ComPtr + { + public: + ComPtr(void): m_i(NULL) {} + ComPtr( const ComPtr< I > &ptr ): m_i(ptr.get()) { + if ( m_i != NULL ) m_i->AddRef(); + } + ~ComPtr(void) { reset(); } + ComPtr< I > &operator=( const ComPtr< I > &other ) { + reset(); + m_i = other.get(); + if ( m_i != NULL ) m_i->AddRef(); + return *this; + }; + I **operator&(void) { + reset(); + return &m_i; + } + void coCreateInstance( REFCLSID clsid, REFIID iid, const char *errorText ) + throw (Error) { + reset(); + COERRORMACRO( CoCreateInstance( clsid, NULL, CLSCTX_INPROC, iid, + (void **)&m_i ), Error, , errorText ); + } + I *get(void) const { return m_i; } + I &operator*(void) { + assert( m_i != NULL ); + return *m_i; + } + I *operator->(void) { + assert( m_i != NULL ); + return m_i; + } + void reset(void) { if ( m_i != NULL ) { m_i->Release(); m_i = NULL; } } + protected: + I *m_i; + }; + +}; + +#endif + +#endif diff --git a/linphone/mediastreamer2/plugins/msdscap/ds3.cc b/linphone/mediastreamer2/plugins/msdscap/ds3.cc new file mode 100644 index 0000000000000000000000000000000000000000..2d8dacfd84819c5e4ca0db864901d34f2c1fb0b0 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/ds3.cc @@ -0,0 +1,702 @@ +// This is a DirectShow interface. But maybe you'll find that it's easier to +// access the camera directly ;) + +// http://www.codeguru.com/cpp/g-m/multimedia/video/article.php/c9551/ +// http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-April/027965.html +// http://msdn2.microsoft.com/en-us/library/ms787594.aspx +// http://msdn2.microsoft.com/en-us/library/ms787867.aspx +// NullRenderer wih reference clock set to NULL +// http://www.videolan.org/ +// http://git.videolan.org/gitweb.cgi?p=vlc.git;f=modules/access/dshow;hb=0.8.6 + +// #include <wtypes.h> +// #include <unknwn.h> +// #include <ole2.h> +// #include <limits.h> +// #include <dshow.h> + +#include <iostream> +#include <iomanip> +#include <fstream> +#include <windows.h> +#include <winnls.h> +#include <errors.h> +#include <initguid.h> +#include <ocidl.h> +#include <malloc.h> +#include "comptr.hh" +#include "error.hh" + +#define FILTER_NAME L"HornetsEye Capture Filter" +#define PIN_NAME L"Capture" + +using namespace Hornetseye; + +DEFINE_GUID( CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, + 0x11d0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); +DEFINE_GUID( CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, + 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 ); +DEFINE_GUID( CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +DEFINE_GUID( CLSID_SampleGrabber, 0xc1f400a0, 0x3f08, 0x11d3, + 0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 ); +DEFINE_GUID( CLSID_NullRenderer,0xc1f400a4, 0x3f08, 0x11d3, + 0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 ); +DEFINE_GUID( CLSID_VfwCapture, 0x1b544c22, 0xfd0b, 0x11ce, + 0x8c, 0x63, 0x0, 0xaa, 0x00, 0x44, 0xb5, 0x1e); +DEFINE_GUID( IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +DEFINE_GUID( IID_IBaseFilter, 0x56a86895, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, + 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 ); +DEFINE_GUID( IID_IEnumFilters, 0x56a86893, 0xad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IEnumPins, 0x56a86892, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaSample, 0x56a8689a, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaFilter, 0x56a86899, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_ISampleGrabber, 0x6b652fff, 0x11fe, 0x4fce, + 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f ); +DEFINE_GUID( IID_ISampleGrabberCB, 0x0579154a, 0x2b53, 0x4994, + 0xb0, 0xd0, 0xe7, 0x73, 0x14, 0x8e, 0xff, 0x85 ); +DEFINE_GUID( IID_IMediaEvent, 0x56a868b6, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMemInputPin, 0x56a8689d, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, + 0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56 ); +DEFINE_GUID( IID_IVideoProcAmp, 0x4050560e, 0x42a7, 0x413a, + 0x85, 0xc2, 0x09, 0x26, 0x9a, 0x2d, 0x0f, 0x44 ); +DEFINE_GUID( MEDIATYPE_Video, 0x73646976, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID( MEDIASUBTYPE_YV12, 0x32315659, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_IYUV, 0x56555949, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_YUYV, 0x56595559, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_YUY2, 0x32595559, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_UYVY, 0x59565955, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_RGB24, 0xe436eb7d, 0x524f, 0x11ce, + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); + +using namespace std; + +typedef LONGLONG REFERENCE_TIME; + +typedef struct tagVIDEOINFOHEADER { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + BITMAPINFOHEADER bmiHeader; +} VIDEOINFOHEADER; + +typedef struct _AMMediaType { + GUID majortype; + GUID subtype; + BOOL bFixedSizeSamples; + BOOL bTemporalCompression; + ULONG lSampleSize; + GUID formattype; + IUnknown *pUnk; + ULONG cbFormat; + BYTE *pbFormat; +} AM_MEDIA_TYPE; + +DECLARE_ENUMERATOR_(IEnumMediaTypes,AM_MEDIA_TYPE*); + +typedef struct _VIDEO_STREAM_CONFIG_CAPS +{ + GUID guid; + ULONG VideoStandard; + SIZE InputSize; + SIZE MinCroppingSize; + SIZE MaxCroppingSize; + int CropGranularityX; + int CropGranularityY; + int CropAlignX; + int CropAlignY; + SIZE MinOutputSize; + SIZE MaxOutputSize; + int OutputGranularityX; + int OutputGranularityY; + int StretchTapsX; + int StretchTapsY; + int ShrinkTapsX; + int ShrinkTapsY; + LONGLONG MinFrameInterval; + LONGLONG MaxFrameInterval; + LONG MinBitsPerSecond; + LONG MaxBitsPerSecond; +} VIDEO_STREAM_CONFIG_CAPS; + +typedef LONGLONG REFERENCE_TIME; + +typedef interface IBaseFilter IBaseFilter; +typedef interface IReferenceClock IReferenceClock; +typedef interface IFilterGraph IFilterGraph; + +typedef enum _FilterState { + State_Stopped, + State_Paused, + State_Running +} FILTER_STATE; + +#define MAX_FILTER_NAME 128 +typedef struct _FilterInfo { + WCHAR achName[MAX_FILTER_NAME]; + IFilterGraph *pGraph; +} FILTER_INFO; + +typedef enum _PinDirection { + PINDIR_INPUT, + PINDIR_OUTPUT +} PIN_DIRECTION; + +#define MAX_PIN_NAME 128 +typedef struct _PinInfo { + IBaseFilter *pFilter; + PIN_DIRECTION dir; + WCHAR achName[MAX_PIN_NAME]; +} PIN_INFO; + +#define INTERFACE IPin +DECLARE_INTERFACE_(IPin,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(ReceiveConnection)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(Disconnect)(THIS) PURE; + STDMETHOD(ConnectedTo)(THIS_ IPin**) PURE; + STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO*) PURE; + STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION*) PURE; +}; +#undef INTERFACE + +DECLARE_ENUMERATOR_(IEnumPins,IPin*); + +typedef struct _AllocatorProperties { + long cBuffers; + long cbBuffer; + long cbAlign; + long cbPrefix; +} ALLOCATOR_PROPERTIES; + +typedef LONG_PTR OAEVENT; + +#define INTERFACE IMediaEvent +DECLARE_INTERFACE_(IMediaEvent,IDispatch) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetEventHandle)(THIS_ OAEVENT*) PURE; + STDMETHOD(GetEvent)(THIS_ long*,LONG_PTR,LONG_PTR,long) PURE; + STDMETHOD(WaitForCompletion)(THIS_ long,long*) PURE; + STDMETHOD(CancelDefaultHandling)(THIS_ long) PURE; + STDMETHOD(RestoreDefaultHandling)(THIS_ long) PURE; + STDMETHOD(FreeEventParams)(THIS_ long,LONG_PTR,LONG_PTR) PURE; +}; +#undef INTERFACE + +typedef long OAFilterState; + +#define INTERFACE IMediaControl +DECLARE_INTERFACE_(IMediaControl,IDispatch) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Run)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetState)(THIS_ LONG,OAFilterState*) PURE; + STDMETHOD(RenderFile)(THIS_ BSTR) PURE; + STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**) PURE; + STDMETHOD(get_FilterCollection)(THIS_ IDispatch**) PURE; + STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**) PURE; + STDMETHOD(StopWhenReady)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IVideoProcAmp +DECLARE_INTERFACE_(IVideoProcAmp,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IAMStreamConfig +DECLARE_INTERFACE_(IAMStreamConfig,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE; + STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE; + STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMediaFilter +DECLARE_INTERFACE_(IMediaFilter,IPersist) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE; + STDMETHOD(GetState)(THIS_ DWORD,FILTER_STATE*) PURE; + STDMETHOD(SetSyncSource)(THIS_ IReferenceClock*) PURE; + STDMETHOD(GetSyncSource)(THIS_ IReferenceClock**) PURE; +}; +#undef INTERFACE + +#define INTERFACE IBaseFilter +DECLARE_INTERFACE_(IBaseFilter,IMediaFilter) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(EnumPins)(THIS_ IEnumPins**) PURE; + STDMETHOD(FindPin)(THIS_ LPCWSTR,IPin**) PURE; + STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO*) PURE; + STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph*,LPCWSTR) PURE; + STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR*) PURE; +}; +#undef INTERFACE + +DECLARE_ENUMERATOR_(IEnumFilters,IBaseFilter*); + +// #define INTERFACE IEnumFilters +// DECLARE_INTERFACE_(IEnumFilters,IUnknown) +// { +// STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; +// STDMETHOD_(ULONG,AddRef)(THIS) PURE; +// STDMETHOD_(ULONG,Release)(THIS) PURE; +// STDMETHOD(Next)(THIS_ ULONG,IBaseFilter**,ULONG*) PURE; +// STDMETHOD(Skip)(THIS_ ULONG) PURE; +// STDMETHOD(Reset)(THIS) PURE; +// STDMETHOD(Clone)(THIS_ IEnumFilters**) PURE; +// }; +// #undef INTERFACE + +#define INTERFACE IFilterGraph +DECLARE_INTERFACE_(IFilterGraph,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(AddFilter)(THIS_ IBaseFilter*,LPCWSTR) PURE; + STDMETHOD(RemoveFilter)(THIS_ IBaseFilter*) PURE; + STDMETHOD(EnumFilters)(THIS_ IEnumFilters**) PURE; + STDMETHOD(FindFilterByName)(THIS_ LPCWSTR,IBaseFilter**) PURE; + STDMETHOD(ConnectDirect)(THIS_ IPin*,IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(Reconnect)(THIS_ IPin*) PURE; + STDMETHOD(Disconnect)(THIS_ IPin*) PURE; + STDMETHOD(SetDefaultSyncSource)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IGraphBuilder +DECLARE_INTERFACE_(IGraphBuilder,IFilterGraph) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin*,IPin*) PURE; + STDMETHOD(Render)(THIS_ IPin*) PURE; + STDMETHOD(RenderFile)(THIS_ LPCWSTR,LPCWSTR) PURE; + STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR,LPCWSTR,IBaseFilter**) PURE; + STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE; + STDMETHOD(Abort)(THIS) PURE; + STDMETHOD(ShouldOperationContinue)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE ICreateDevEnum +DECLARE_INTERFACE_(ICreateDevEnum,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(CreateClassEnumerator)(THIS_ REFIID,IEnumMoniker**,DWORD) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMediaSample +DECLARE_INTERFACE_(IMediaSample,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMemAllocator +DECLARE_INTERFACE_(IMemAllocator,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES*,ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(Commit)(THIS) PURE; + STDMETHOD(Decommit)(THIS) PURE; + STDMETHOD(GetBuffer)(THIS_ IMediaSample **,REFERENCE_TIME*,REFERENCE_TIME*,DWORD) PURE; + STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample*) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMemInputPin +DECLARE_INTERFACE_(IMemInputPin,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetAllocator)(THIS_ IMemAllocator**) PURE; + STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator*,BOOL) PURE; + STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(Receive)(THIS_ IMediaSample*) PURE; + STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample**,LONG,LONG*) PURE; + STDMETHOD(ReceiveCanBlock)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE ISampleGrabberCB +DECLARE_INTERFACE_(ISampleGrabberCB,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SampleCB)(THIS_ double,IMediaSample*) PURE; + STDMETHOD(BufferCB)(THIS_ double,BYTE*,long) PURE; +}; +#undef INTERFACE + +#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 + +ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num ) +{ + ComPtr< IPin > retVal; + ComPtr< IEnumPins > enumPins; + COERRORMACRO( filter->EnumPins( &enumPins ), Error, , + "Error getting pin enumerator" ); + ULONG found; + ComPtr< IPin > pin; + while ( enumPins->Next( 1, &pin, &found ) == S_OK ) { + PIN_DIRECTION pinDirection = (PIN_DIRECTION)( -1 ); + pin->QueryDirection( &pinDirection ); + if ( pinDirection == direction ) { + if ( num == 0 ) { + retVal = pin; + break; + }; + num--; + }; + }; + return retVal; +} + +class Callback: public ISampleGrabberCB +{ +public: + Callback(void); + virtual ~Callback(void); + STDMETHODIMP QueryInterface( REFIID riid, void **ppv ); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + STDMETHODIMP SampleCB(double,IMediaSample*); + STDMETHODIMP BufferCB(double,BYTE*,long); +protected: + long m_refCount; +}; + +Callback::Callback(void): m_refCount(1) +{ +#ifndef NDEBUG + cerr << "Callback::Callback" << endl; +#endif +} + +Callback::~Callback(void) +{ +#ifndef NDEBUG + cerr << "Callback::~Callback" << endl; +#endif +} + +STDMETHODIMP Callback::QueryInterface(REFIID riid, void **ppv) +{ +#ifndef NDEBUG + cerr << "Callback::QueryInterface" << endl; +#endif + HRESULT retval; + if ( ppv == NULL ) return E_POINTER; + /* + if ( riid == IID_IUnknown ) { + *ppv = static_cast< IUnknown * >( this ); + AddRef(); + retval = S_OK; + } else if ( riid == IID_ISampleGrabberCB ) { + *ppv = static_cast< ISampleGrabberCB * >( this ); + AddRef(); + retval = S_OK; + } else */ { +#ifndef NDEBUG + cerr << setbase( 16 ) << setfill('0') + << "DEFINE_GUID( ..., 0x" << setw(8) << (int)riid.Data1 << ", 0x" + << setw(4) << (int)riid.Data2 << "," << endl + << " 0x" + << setw(4) << (int)riid.Data3 << ", 0x" << setw(2) + << (int)riid.Data4[0] << ", 0x" + << (int)riid.Data4[1] << ", 0x" + << (int)riid.Data4[2] << ", 0x" + << (int)riid.Data4[3] << ", 0x" + << (int)riid.Data4[4] << ", 0x" + << (int)riid.Data4[5] << ", 0x" + << (int)riid.Data4[6] << ", 0x" + << (int)riid.Data4[7] << " ) ?" << endl + << setfill( ' ' ) << setw( 0 ) << setbase( 10 ); +#endif + retval = E_NOINTERFACE; + }; + return retval; +}; + +STDMETHODIMP_(ULONG) Callback::AddRef(void) +{ +#ifndef NDEBUG + cerr << "Callback::AddRef" << endl; +#endif + m_refCount++; + return m_refCount; +} + +STDMETHODIMP_(ULONG) Callback::Release(void) +{ +#ifndef NDEBUG + cerr << "Callback::Release" << endl; +#endif + if ( !InterlockedDecrement( &m_refCount ) ) delete this; + return m_refCount; +} + +STDMETHODIMP Callback::SampleCB( double, IMediaSample * ) +{ +#ifndef NDEBUG + cerr << "Callback::SampleCB" << endl; +#endif + return S_OK; +} + +STDMETHODIMP Callback::BufferCB( double, BYTE *, long ) +{ +#ifndef NDEBUG + cerr << "Callback::BufferCB" << endl; +#endif + return E_NOTIMPL; +} + +using namespace std; + +int main(void) +{ + int retVal = 0; + bool initialized = false; + Callback *callback = NULL; + try { + COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); + initialized = true; + ComPtr< IGraphBuilder > graphBuilder; + graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder, + "Could not create graph builder " + "interface" ); + cerr << "graphBuilder is " << graphBuilder.get() << endl; + ComPtr< ICreateDevEnum > createDevEnum; + createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum, + IID_ICreateDevEnum, "Could not create " + "device enumerator" ); + ComPtr< IEnumMoniker > enumMoniker; + COERRORMACRO( createDevEnum->CreateClassEnumerator + ( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 ), Error, , + "Error requesting moniker enumerator" ); + createDevEnum.reset(); + COERRORMACRO( enumMoniker->Reset(), Error, , + "Error resetting moniker enumerator" ); + int index = 0; + ComPtr< IMoniker > moniker; + for ( int i=0; i<=index; i++ ) { + ULONG fetched = 0; + COERRORMACRO( enumMoniker->Next( 1, &moniker, &fetched ), Error, , + "Error fetching next moniker" ); + }; + enumMoniker.reset(); + ComPtr< IBaseFilter > source; + COERRORMACRO( moniker->BindToObject( 0, 0, IID_IBaseFilter, + (void **)&source ), Error, , + "Error binding moniker to base filter" ); + moniker.reset(); + COERRORMACRO( graphBuilder->AddFilter( source.get(), L"Source" ), + Error, , "Error adding camera source to filter graph" ); + ComPtr< IPin > sourceOut = getPin( source.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( sourceOut.get() != NULL, Error, , + "Error getting output pin of camera source" ); + ComPtr< IAMStreamConfig > streamConfig; + COERRORMACRO( sourceOut-> + QueryInterface( IID_IAMStreamConfig, + (void **)&streamConfig ), + Error, , "Error requesting stream configuration API" ); + int count, size; + COERRORMACRO( streamConfig->GetNumberOfCapabilities( &count, &size ), + Error, , "Error getting number of capabilities" ); + bool ok = false; + for ( int i=0; i<count; i++ ) { + VIDEO_STREAM_CONFIG_CAPS videoConfig; + AM_MEDIA_TYPE *mediaType; + COERRORMACRO( streamConfig->GetStreamCaps( i, &mediaType, + (BYTE *)&videoConfig ), + Error, , "Error getting stream capabilities" ); + if ( mediaType->majortype == MEDIATYPE_Video && + mediaType->cbFormat != 0 ) { + VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat; + // TODO: choose format here !!! + cerr << "Setting format " << infoHeader->bmiHeader.biWidth + << "x" << infoHeader->bmiHeader.biHeight << endl; + streamConfig->SetFormat( mediaType ); + ok = true; + }; + if ( mediaType->cbFormat != 0 ) + CoTaskMemFree( (PVOID)mediaType->pbFormat ); + if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release(); + CoTaskMemFree( (PVOID)mediaType ); + if ( ok ) + break; + }; + streamConfig.reset(); + ERRORMACRO( ok, Error, , "Could not find any video format" ); + + ComPtr< IBaseFilter > grabberBase; + COERRORMACRO( CoCreateInstance( CLSID_SampleGrabber, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&grabberBase ), + Error, , "Error creating sample grabber" ); + COERRORMACRO( graphBuilder->AddFilter( grabberBase.get(), L"Grabber" ), + Error, , "Error adding sample grabber to filter graph" ); + ComPtr< ISampleGrabber > sampleGrabber; + COERRORMACRO( grabberBase->QueryInterface( IID_ISampleGrabber, + (void **)&sampleGrabber ), + Error, , "Error requesting sample grabber interface" ); + COERRORMACRO( sampleGrabber->SetOneShot( FALSE ), Error, , + "Error disabling one-shot mode" ); + COERRORMACRO( sampleGrabber->SetBufferSamples( TRUE ), Error, , + "Error enabling buffer sampling" ); + callback = new Callback; + COERRORMACRO( sampleGrabber->SetCallBack( callback, 0 ), Error, , + "Error setting callback interface for grabbing" ); + ComPtr< IPin > grabberIn = getPin( grabberBase.get(), PINDIR_INPUT, 0 ); + ERRORMACRO( grabberIn.get() != NULL, Error, , + "Error getting input of sample grabber" ); + ComPtr< IPin > grabberOut = getPin( grabberBase.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( grabberOut.get() != NULL, Error, , + "Error getting output of sample grabber" ); + + ComPtr< IBaseFilter > nullRenderer; + COERRORMACRO( CoCreateInstance( CLSID_NullRenderer, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&nullRenderer ), + Error, , "Error creating Null Renderer" ); + COERRORMACRO( graphBuilder->AddFilter( nullRenderer.get(), L"Sink" ), + Error, , "Error adding null renderer to filter graph" ); + ComPtr< IPin > nullIn = getPin( nullRenderer.get(), PINDIR_INPUT, 0 ); + + cerr << endl << "Attempting to connect" << endl; + COERRORMACRO( graphBuilder->Connect( sourceOut.get(), grabberIn.get() ), + Error, , "Error connecting source to sample grabber" ); + COERRORMACRO( graphBuilder->Connect( grabberOut.get(), nullIn.get() ), + Error, , "Error connecting sample grabber to sink" ); + + cerr << "Success!!!!!!!!!!!!!!!!!!!!!" << endl; + + ComPtr< IMediaControl > mediaControl; + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaControl, + (void **)&mediaControl ), + Error, , "Error requesting media control interface" ); + COERRORMACRO( mediaControl->Run(), Error, , "Error running graph" ); + + ComPtr< IMediaEvent > mediaEvent; + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaEvent, + (void **)&mediaEvent ), + Error, , "Error requesting event interface" ); + + cin.get(); + + mediaControl->Stop(); + + long evCode = 0; + mediaEvent->WaitForCompletion( INFINITE, &evCode ); + + // sourceOut.reset(); + // sinkIn.reset(); + // source.reset(); + } catch ( Error &e ) { + cerr << e.what() << endl; + retVal = 1; + }; + if ( callback != NULL ) callback->Release(); + if ( initialized ) CoUninitialize(); + return retVal; +} + +static void ms_dshow_detect(MSWebCamManager *obj); + +static MSWebCamDesc ms_dshow_cam_desc={ + "Directshow capture", + &ms_dshow_detect, + NULL, + &ms_dshow_create_reader, + NULL +}; + +static void ms_dshow_detect(MSWebCamManager *obj){ + int i; + MSWebCam *cam; +} + +extern "C" void libmsdscap_init(void){ + ms_web_cam_desc_register(&ms_dshow_cam_desc); +} diff --git a/linphone/mediastreamer2/plugins/msdscap/error.cc b/linphone/mediastreamer2/plugins/msdscap/error.cc new file mode 100644 index 0000000000000000000000000000000000000000..1365a4eca27c7b85b35b1e26e75678859a01ce32 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/error.cc @@ -0,0 +1,23 @@ +/* HornetsEye - Computer Vision with Ruby + Copyright (C) 2006, 2007 Jan Wedekind + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "error.hh" + +using namespace std; + +namespace Hornetseye { + string Error::temp; +}; + diff --git a/linphone/mediastreamer2/plugins/msdscap/error.hh b/linphone/mediastreamer2/plugins/msdscap/error.hh new file mode 100644 index 0000000000000000000000000000000000000000..453c6e74831fa1bd76983b816fa8afc6ff039916 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/error.hh @@ -0,0 +1,133 @@ +/* HornetsEye - Computer Vision with Ruby + Copyright (C) 2006, 2007 Jan Wedekind + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifndef HORNETSEYE_ERROR_HH +#define HORNETSEYE_ERROR_HH + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <exception> +#include <sstream> +#include <string> +#ifdef WIN32 +#include <stdio.h> +#include <windef.h> +#include <wchar.h> +#include <winsock.h> +#endif + +namespace Hornetseye { + + /** Exception class deriving from std::exception. + This class provides a syntax similar to output-streams for convenience. + For compability with other libraries it is inheriting the class + \c std::exception. + + Here is an example how to use an instance of this class in C++: + \include exceptiontest/exceptiontest.cc + + Exception-handling also can be done using the macro \c ERRORMACRO: + \include exceptiontest/macrotest.cc + + Mind that the macro uses a variable with the name \c _e. Make sure, that + you don't use this variable-name in any of the macro-arguments! + + Ruby already comes with exception classes: + \include exceptiontest/exceptiontest.rb + + @date Mon Aug 23 14:37:05 UTC 2004 */ + class Error: public std::exception + { + public: + /// Constructor. + Error(void) {} + /// Copy constructor. + Error( Error &e ): std::exception( e ) + { m_message << e.m_message.str(); } + /// Destructor. + virtual ~Error(void) throw() {} + /// + template< typename T > + std::ostream &operator<<( const T &t ) + { m_message << t; return m_message; } + /** Interface for manipulators. + Manipulators such as \c std::endl and \c std::hex use these + functions in constructs like "Error e; e << std::endl". + For more information, see the iomanip header. */ + std::ostream &operator<<( std::ostream& (*__pf)( std::ostream&) ) + { (*__pf)( m_message ); return m_message; } + /// Returns error message (not thread safe). + virtual const char* what(void) const throw() { + temp = m_message.str(); + return temp.c_str(); + return NULL; + } + protected: + /// Memory-stream containing the error message. + std::ostringstream m_message; + /** Temporary to do null-termination. + The method \c what() requires a null-terminated string. */ + static std::string temp; + }; + +}; + +#define ERRORMACRO( condition, class, params, message ) \ + if ( !( condition ) ) { \ + class _e params; \ + _e << message; \ + throw _e; \ + }; + +#ifdef WIN32 +#define COERRORMACRO( condition, class, params, message ) \ + { \ + HRESULT _hr = condition; \ + if ( FAILED( _hr ) ) { \ + class _e params; \ + _e << message; \ + TCHAR *_msg; \ + if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM, 0, _hr, 0, \ + (LPTSTR)&_msg, 0, NULL ) != 0 ) { \ + _e << ": " << _msg; \ + LocalFree( _msg ); \ + }; \ + throw _e; \ + }; \ + }; + +#define W32ERRORMACRO( condition, class, params, message ) \ + { \ + if ( !( condition ) ) { \ + class _e params; \ + _e << message; \ + TCHAR *_msg; \ + DWORD _errCode = GetLastError(); \ + if ( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | \ + FORMAT_MESSAGE_FROM_SYSTEM, 0, _errCode, 0, \ + (LPTSTR)&_msg, 0, NULL ) != 0 ) { \ + _e << ": " << _msg; \ + LocalFree( _msg ); \ + }; \ + throw _e; \ + }; \ + }; + +#endif + +#endif diff --git a/linphone/mediastreamer2/plugins/msdscap/libmsdscap.dev b/linphone/mediastreamer2/plugins/msdscap/libmsdscap.dev new file mode 100755 index 0000000000000000000000000000000000000000..a54e05e6703739b13bb7b89d6a2497a843bd00c4 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/libmsdscap.dev @@ -0,0 +1,125 @@ +[Project] +FileName=libmsdscap.dev +Name=libmsdscap +UnitCount=4 +PchHead=-1 +PchSource=-1 +Ver=3 +IsCpp=1 +ProfilesCount=2 +ProfileIndex=0 +Folders= + +[Unit1] +FileName=error.hh +CompileCpp=1 +Folder=libmsdscap +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit2] +FileName=comptr.hh +CompileCpp=1 +Folder=libmsdscap +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit3] +FileName=mdscap.cc +CompileCpp=1 +Folder=libmsdscap +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[Unit4] +FileName=error.cc +CompileCpp=1 +Folder=libmsdscap +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription= +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNrOnRebuild=0 +AutoIncBuildNrOnCompile=0 + +[Profile1] +ProfileName=MingW 3.4.2 +Type=3 +ObjFiles= +Includes=../../include;../../../oRTP/include +Libs=../../build/win32native/;../../../oRTP/build/win32native +ResourceIncludes= +MakeIncludes= +Compiler=-DBUILDING_DLL=1_@@_-DORTP_INET6_@@_ +CppCompiler=-DBUILDING_DLL=1_@@_ +Linker=--no-export-all-symbols_@@_--add-stdcall-alias_@@_-lole32_@@_-loleaut32_@@_-lwinmm_@@_-luuid_@@_-lmediastreamer2_@@_-lortp_@@_ +PreprocDefines= +CompilerSettings=0000000001001000000000 +Icon= +ExeOutput= +ObjectOutput=Output\MingW +OverrideOutput=0 +OverrideOutputName=libmsdscap.dll +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +compilerType=0 + +[Profile2] +ProfileName=Visual C++ 2005 +Type=3 +ObjFiles= +Includes= +Libs= +ResourceIncludes= +MakeIncludes= +Compiler=/DBUILDING_DLL=1 +CppCompiler=/DBUILDING_DLL=1 +Linker= +PreprocDefines= +CompilerSettings=000000000000010000000000000000000000 +Icon= +ExeOutput=Output\Visual C++ 2005 +ObjectOutput=Objects\Visual C++ 2005 +OverrideOutput=0 +OverrideOutputName= +HostApplication= +CommandLine= +UseCustomMakefile=0 +CustomMakefile= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=1 +compilerType=1 + diff --git a/linphone/mediastreamer2/plugins/msdscap/mdscap.cc b/linphone/mediastreamer2/plugins/msdscap/mdscap.cc new file mode 100755 index 0000000000000000000000000000000000000000..a03f2e2106af7b82a18ce8d8785e4f8d76952b48 --- /dev/null +++ b/linphone/mediastreamer2/plugins/msdscap/mdscap.cc @@ -0,0 +1,885 @@ +// This is a DirectShow interface. But maybe you'll find that it's easier to +// access the camera directly ;) + +// http://www.codeguru.com/cpp/g-m/multimedia/video/article.php/c9551/ +// http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-April/027965.html +// http://msdn2.microsoft.com/en-us/library/ms787594.aspx +// http://msdn2.microsoft.com/en-us/library/ms787867.aspx +// NullRenderer wih reference clock set to NULL +// http://www.videolan.org/ +// http://git.videolan.org/gitweb.cgi?p=vlc.git;f=modules/access/dshow;hb=0.8.6 + +// #include <wtypes.h> +// #include <unknwn.h> +// #include <ole2.h> +// #include <limits.h> +// #include <dshow.h> + +#include <iostream> +#include <iomanip> +#include <fstream> +#include <windows.h> +#include <winnls.h> +#include <errors.h> +#include <initguid.h> +#include <ocidl.h> +#include <malloc.h> +#include "comptr.hh" +#include "error.hh" + +#include <mediastreamer2/mswebcam.h> +#include <mediastreamer2/msfilter.h> +#include <mediastreamer2/msticker.h> +#include <mediastreamer2/msvideo.h> + +#define FILTER_NAME L"HornetsEye Capture Filter" +#define PIN_NAME L"Capture" + +using namespace Hornetseye; + +DEFINE_GUID( CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01, + 0x11d0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86); +DEFINE_GUID( CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0, + 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 ); +DEFINE_GUID( CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce, + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +DEFINE_GUID( CLSID_SampleGrabber, 0xc1f400a0, 0x3f08, 0x11d3, + 0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 ); +DEFINE_GUID( CLSID_NullRenderer,0xc1f400a4, 0x3f08, 0x11d3, + 0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 ); +DEFINE_GUID( CLSID_VfwCapture, 0x1b544c22, 0xfd0b, 0x11ce, + 0x8c, 0x63, 0x0, 0xaa, 0x00, 0x44, 0xb5, 0x1e); +DEFINE_GUID( IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70); +DEFINE_GUID( IID_IBaseFilter, 0x56a86895, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0, + 0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 ); +DEFINE_GUID( IID_IEnumFilters, 0x56a86893, 0xad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IEnumPins, 0x56a86892, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaSample, 0x56a8689a, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaFilter, 0x56a86899, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IPin, 0x56a86891, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_ISampleGrabber, 0x6b652fff, 0x11fe, 0x4fce, + 0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f ); +DEFINE_GUID( IID_ISampleGrabberCB, 0x0579154a, 0x2b53, 0x4994, + 0xb0, 0xd0, 0xe7, 0x73, 0x14, 0x8e, 0xff, 0x85 ); +DEFINE_GUID( IID_IMediaEvent, 0x56a868b6, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IMemInputPin, 0x56a8689d, 0x0ad4, 0x11ce, + 0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); +DEFINE_GUID( IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0, + 0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56 ); +DEFINE_GUID( IID_IVideoProcAmp, 0x4050560e, 0x42a7, 0x413a, + 0x85, 0xc2, 0x09, 0x26, 0x9a, 0x2d, 0x0f, 0x44 ); +DEFINE_GUID( MEDIATYPE_Video, 0x73646976, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +DEFINE_GUID( MEDIASUBTYPE_YV12, 0x32315659, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_IYUV, 0x56555949, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_YUYV, 0x56595559, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_YUY2, 0x32595559, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_UYVY, 0x59565955, 0x0000, 0x0010, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 ); +DEFINE_GUID( MEDIASUBTYPE_RGB24, 0xe436eb7d, 0x524f, 0x11ce, + 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 ); + +using namespace std; + +typedef LONGLONG REFERENCE_TIME; + +typedef struct tagVIDEOINFOHEADER { + RECT rcSource; + RECT rcTarget; + DWORD dwBitRate; + DWORD dwBitErrorRate; + REFERENCE_TIME AvgTimePerFrame; + BITMAPINFOHEADER bmiHeader; +} VIDEOINFOHEADER; + +typedef struct _AMMediaType { + GUID majortype; + GUID subtype; + BOOL bFixedSizeSamples; + BOOL bTemporalCompression; + ULONG lSampleSize; + GUID formattype; + IUnknown *pUnk; + ULONG cbFormat; + BYTE *pbFormat; +} AM_MEDIA_TYPE; + +DECLARE_ENUMERATOR_(IEnumMediaTypes,AM_MEDIA_TYPE*); + +typedef struct _VIDEO_STREAM_CONFIG_CAPS +{ + GUID guid; + ULONG VideoStandard; + SIZE InputSize; + SIZE MinCroppingSize; + SIZE MaxCroppingSize; + int CropGranularityX; + int CropGranularityY; + int CropAlignX; + int CropAlignY; + SIZE MinOutputSize; + SIZE MaxOutputSize; + int OutputGranularityX; + int OutputGranularityY; + int StretchTapsX; + int StretchTapsY; + int ShrinkTapsX; + int ShrinkTapsY; + LONGLONG MinFrameInterval; + LONGLONG MaxFrameInterval; + LONG MinBitsPerSecond; + LONG MaxBitsPerSecond; +} VIDEO_STREAM_CONFIG_CAPS; + +typedef LONGLONG REFERENCE_TIME; + +typedef interface IBaseFilter IBaseFilter; +typedef interface IReferenceClock IReferenceClock; +typedef interface IFilterGraph IFilterGraph; + +typedef enum _FilterState { + State_Stopped, + State_Paused, + State_Running +} FILTER_STATE; + +#define MAX_FILTER_NAME 128 +typedef struct _FilterInfo { + WCHAR achName[MAX_FILTER_NAME]; + IFilterGraph *pGraph; +} FILTER_INFO; + +typedef enum _PinDirection { + PINDIR_INPUT, + PINDIR_OUTPUT +} PIN_DIRECTION; + +#define MAX_PIN_NAME 128 +typedef struct _PinInfo { + IBaseFilter *pFilter; + PIN_DIRECTION dir; + WCHAR achName[MAX_PIN_NAME]; +} PIN_INFO; + +#define INTERFACE IPin +DECLARE_INTERFACE_(IPin,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(ReceiveConnection)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(Disconnect)(THIS) PURE; + STDMETHOD(ConnectedTo)(THIS_ IPin**) PURE; + STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO*) PURE; + STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION*) PURE; +}; +#undef INTERFACE + +DECLARE_ENUMERATOR_(IEnumPins,IPin*); + +typedef struct _AllocatorProperties { + long cBuffers; + long cbBuffer; + long cbAlign; + long cbPrefix; +} ALLOCATOR_PROPERTIES; + +typedef LONG_PTR OAEVENT; + +#define INTERFACE IMediaEvent +DECLARE_INTERFACE_(IMediaEvent,IDispatch) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetEventHandle)(THIS_ OAEVENT*) PURE; + STDMETHOD(GetEvent)(THIS_ long*,LONG_PTR,LONG_PTR,long) PURE; + STDMETHOD(WaitForCompletion)(THIS_ long,long*) PURE; + STDMETHOD(CancelDefaultHandling)(THIS_ long) PURE; + STDMETHOD(RestoreDefaultHandling)(THIS_ long) PURE; + STDMETHOD(FreeEventParams)(THIS_ long,LONG_PTR,LONG_PTR) PURE; +}; +#undef INTERFACE + +typedef long OAFilterState; + +#define INTERFACE IMediaControl +DECLARE_INTERFACE_(IMediaControl,IDispatch) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Run)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetState)(THIS_ LONG,OAFilterState*) PURE; + STDMETHOD(RenderFile)(THIS_ BSTR) PURE; + STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**) PURE; + STDMETHOD(get_FilterCollection)(THIS_ IDispatch**) PURE; + STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**) PURE; + STDMETHOD(StopWhenReady)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IVideoProcAmp +DECLARE_INTERFACE_(IVideoProcAmp,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IAMStreamConfig +DECLARE_INTERFACE_(IAMStreamConfig,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE; + STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE; + STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE; + STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMediaFilter +DECLARE_INTERFACE_(IMediaFilter,IPersist) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(Pause)(THIS) PURE; + STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE; + STDMETHOD(GetState)(THIS_ DWORD,FILTER_STATE*) PURE; + STDMETHOD(SetSyncSource)(THIS_ IReferenceClock*) PURE; + STDMETHOD(GetSyncSource)(THIS_ IReferenceClock**) PURE; +}; +#undef INTERFACE + +#define INTERFACE IBaseFilter +DECLARE_INTERFACE_(IBaseFilter,IMediaFilter) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(EnumPins)(THIS_ IEnumPins**) PURE; + STDMETHOD(FindPin)(THIS_ LPCWSTR,IPin**) PURE; + STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO*) PURE; + STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph*,LPCWSTR) PURE; + STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR*) PURE; +}; +#undef INTERFACE + +DECLARE_ENUMERATOR_(IEnumFilters,IBaseFilter*); + +// #define INTERFACE IEnumFilters +// DECLARE_INTERFACE_(IEnumFilters,IUnknown) +// { +// STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; +// STDMETHOD_(ULONG,AddRef)(THIS) PURE; +// STDMETHOD_(ULONG,Release)(THIS) PURE; +// STDMETHOD(Next)(THIS_ ULONG,IBaseFilter**,ULONG*) PURE; +// STDMETHOD(Skip)(THIS_ ULONG) PURE; +// STDMETHOD(Reset)(THIS) PURE; +// STDMETHOD(Clone)(THIS_ IEnumFilters**) PURE; +// }; +// #undef INTERFACE + +#define INTERFACE IFilterGraph +DECLARE_INTERFACE_(IFilterGraph,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(AddFilter)(THIS_ IBaseFilter*,LPCWSTR) PURE; + STDMETHOD(RemoveFilter)(THIS_ IBaseFilter*) PURE; + STDMETHOD(EnumFilters)(THIS_ IEnumFilters**) PURE; + STDMETHOD(FindFilterByName)(THIS_ LPCWSTR,IBaseFilter**) PURE; + STDMETHOD(ConnectDirect)(THIS_ IPin*,IPin*,const AM_MEDIA_TYPE*) PURE; + STDMETHOD(Reconnect)(THIS_ IPin*) PURE; + STDMETHOD(Disconnect)(THIS_ IPin*) PURE; + STDMETHOD(SetDefaultSyncSource)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IGraphBuilder +DECLARE_INTERFACE_(IGraphBuilder,IFilterGraph) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(Connect)(THIS_ IPin*,IPin*) PURE; + STDMETHOD(Render)(THIS_ IPin*) PURE; + STDMETHOD(RenderFile)(THIS_ LPCWSTR,LPCWSTR) PURE; + STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR,LPCWSTR,IBaseFilter**) PURE; + STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE; + STDMETHOD(Abort)(THIS) PURE; + STDMETHOD(ShouldOperationContinue)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE ICreateDevEnum +DECLARE_INTERFACE_(ICreateDevEnum,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(CreateClassEnumerator)(THIS_ REFIID,IEnumMoniker**,DWORD) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMediaSample +DECLARE_INTERFACE_(IMediaSample,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMemAllocator +DECLARE_INTERFACE_(IMemAllocator,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES*,ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(Commit)(THIS) PURE; + STDMETHOD(Decommit)(THIS) PURE; + STDMETHOD(GetBuffer)(THIS_ IMediaSample **,REFERENCE_TIME*,REFERENCE_TIME*,DWORD) PURE; + STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample*) PURE; +}; +#undef INTERFACE + +#define INTERFACE IMemInputPin +DECLARE_INTERFACE_(IMemInputPin,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(GetAllocator)(THIS_ IMemAllocator**) PURE; + STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator*,BOOL) PURE; + STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES*) PURE; + STDMETHOD(Receive)(THIS_ IMediaSample*) PURE; + STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample**,LONG,LONG*) PURE; + STDMETHOD(ReceiveCanBlock)(THIS) PURE; +}; +#undef INTERFACE + +#define INTERFACE ISampleGrabberCB +DECLARE_INTERFACE_(ISampleGrabberCB,IUnknown) +{ + STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + STDMETHOD(SampleCB)(THIS_ double,IMediaSample*) PURE; + STDMETHOD(BufferCB)(THIS_ double,BYTE*,long) PURE; +}; +#undef INTERFACE + +#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 + +ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num ) +{ + ComPtr< IPin > retVal; + ComPtr< IEnumPins > enumPins; + COERRORMACRO( filter->EnumPins( &enumPins ), Error, , + "Error getting pin enumerator" ); + ULONG found; + ComPtr< IPin > pin; + while ( enumPins->Next( 1, &pin, &found ) == S_OK ) { + PIN_DIRECTION pinDirection = (PIN_DIRECTION)( -1 ); + pin->QueryDirection( &pinDirection ); + if ( pinDirection == direction ) { + if ( num == 0 ) { + retVal = pin; + break; + }; + num--; + }; + }; + return retVal; +} + +class Callback: public ISampleGrabberCB +{ +public: + Callback(void); + virtual ~Callback(void); + STDMETHODIMP QueryInterface( REFIID riid, void **ppv ); + STDMETHODIMP_(ULONG) AddRef(void); + STDMETHODIMP_(ULONG) Release(void); + STDMETHODIMP SampleCB(double,IMediaSample*); + STDMETHODIMP BufferCB(double,BYTE*,long); +protected: + long m_refCount; +}; + +Callback::Callback(void): m_refCount(1) +{ +#ifndef NDEBUG + cerr << "Callback::Callback" << endl; +#endif +} + +Callback::~Callback(void) +{ +#ifndef NDEBUG + cerr << "Callback::~Callback" << endl; +#endif +} + +STDMETHODIMP Callback::QueryInterface(REFIID riid, void **ppv) +{ +#ifndef NDEBUG + cerr << "Callback::QueryInterface" << endl; +#endif + HRESULT retval; + if ( ppv == NULL ) return E_POINTER; + /* + if ( riid == IID_IUnknown ) { + *ppv = static_cast< IUnknown * >( this ); + AddRef(); + retval = S_OK; + } else if ( riid == IID_ISampleGrabberCB ) { + *ppv = static_cast< ISampleGrabberCB * >( this ); + AddRef(); + retval = S_OK; + } else */ { +#ifndef NDEBUG + cerr << setbase( 16 ) << setfill('0') + << "DEFINE_GUID( ..., 0x" << setw(8) << (int)riid.Data1 << ", 0x" + << setw(4) << (int)riid.Data2 << "," << endl + << " 0x" + << setw(4) << (int)riid.Data3 << ", 0x" << setw(2) + << (int)riid.Data4[0] << ", 0x" + << (int)riid.Data4[1] << ", 0x" + << (int)riid.Data4[2] << ", 0x" + << (int)riid.Data4[3] << ", 0x" + << (int)riid.Data4[4] << ", 0x" + << (int)riid.Data4[5] << ", 0x" + << (int)riid.Data4[6] << ", 0x" + << (int)riid.Data4[7] << " ) ?" << endl + << setfill( ' ' ) << setw( 0 ) << setbase( 10 ); +#endif + retval = E_NOINTERFACE; + }; + return retval; +}; + +STDMETHODIMP_(ULONG) Callback::AddRef(void) +{ +#ifndef NDEBUG + cerr << "Callback::AddRef" << endl; +#endif + m_refCount++; + return m_refCount; +} + +STDMETHODIMP_(ULONG) Callback::Release(void) +{ +#ifndef NDEBUG + cerr << "Callback::Release" << endl; +#endif + if ( !InterlockedDecrement( &m_refCount ) ) delete this; + return m_refCount; +} + +STDMETHODIMP Callback::SampleCB( double, IMediaSample * ) +{ +#ifndef NDEBUG + cerr << "Callback::SampleCB" << endl; +#endif + return S_OK; +} + +STDMETHODIMP Callback::BufferCB( double, BYTE *, long ) +{ +#ifndef NDEBUG + cerr << "Callback::BufferCB" << endl; +#endif + return E_NOTIMPL; +} + +using namespace std; + +int toto(void) +{ + int retVal = 0; + bool initialized = false; + Callback *callback = NULL; + try { + COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); + initialized = true; + ComPtr< IGraphBuilder > graphBuilder; + graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder, + "Could not create graph builder " + "interface" ); + cerr << "graphBuilder is " << graphBuilder.get() << endl; + ComPtr< ICreateDevEnum > createDevEnum; + createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum, + IID_ICreateDevEnum, "Could not create " + "device enumerator" ); + ComPtr< IEnumMoniker > enumMoniker; + COERRORMACRO( createDevEnum->CreateClassEnumerator + ( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 ), Error, , + "Error requesting moniker enumerator" ); + createDevEnum.reset(); + COERRORMACRO( enumMoniker->Reset(), Error, , + "Error resetting moniker enumerator" ); + int index = 0; + ComPtr< IMoniker > moniker; + for ( int i=0; i<=index; i++ ) { + ULONG fetched = 0; + COERRORMACRO( enumMoniker->Next( 1, &moniker, &fetched ), Error, , + "Error fetching next moniker" ); + }; + enumMoniker.reset(); + ComPtr< IBaseFilter > source; + COERRORMACRO( moniker->BindToObject( 0, 0, IID_IBaseFilter, + (void **)&source ), Error, , + "Error binding moniker to base filter" ); + moniker.reset(); + COERRORMACRO( graphBuilder->AddFilter( source.get(), L"Source" ), + Error, , "Error adding camera source to filter graph" ); + ComPtr< IPin > sourceOut = getPin( source.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( sourceOut.get() != NULL, Error, , + "Error getting output pin of camera source" ); + ComPtr< IAMStreamConfig > streamConfig; + COERRORMACRO( sourceOut-> + QueryInterface( IID_IAMStreamConfig, + (void **)&streamConfig ), + Error, , "Error requesting stream configuration API" ); + int count, size; + COERRORMACRO( streamConfig->GetNumberOfCapabilities( &count, &size ), + Error, , "Error getting number of capabilities" ); + bool ok = false; + for ( int i=0; i<count; i++ ) { + VIDEO_STREAM_CONFIG_CAPS videoConfig; + AM_MEDIA_TYPE *mediaType; + COERRORMACRO( streamConfig->GetStreamCaps( i, &mediaType, + (BYTE *)&videoConfig ), + Error, , "Error getting stream capabilities" ); + if ( mediaType->majortype == MEDIATYPE_Video && + mediaType->cbFormat != 0 ) { + VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat; + // TODO: choose format here !!! + cerr << "Setting format " << infoHeader->bmiHeader.biWidth + << "x" << infoHeader->bmiHeader.biHeight << endl; + streamConfig->SetFormat( mediaType ); + ok = true; + }; + if ( mediaType->cbFormat != 0 ) + CoTaskMemFree( (PVOID)mediaType->pbFormat ); + if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release(); + CoTaskMemFree( (PVOID)mediaType ); + if ( ok ) + break; + }; + streamConfig.reset(); + ERRORMACRO( ok, Error, , "Could not find any video format" ); + + ComPtr< IBaseFilter > grabberBase; + COERRORMACRO( CoCreateInstance( CLSID_SampleGrabber, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&grabberBase ), + Error, , "Error creating sample grabber" ); + COERRORMACRO( graphBuilder->AddFilter( grabberBase.get(), L"Grabber" ), + Error, , "Error adding sample grabber to filter graph" ); + ComPtr< ISampleGrabber > sampleGrabber; + COERRORMACRO( grabberBase->QueryInterface( IID_ISampleGrabber, + (void **)&sampleGrabber ), + Error, , "Error requesting sample grabber interface" ); + COERRORMACRO( sampleGrabber->SetOneShot( FALSE ), Error, , + "Error disabling one-shot mode" ); + COERRORMACRO( sampleGrabber->SetBufferSamples( TRUE ), Error, , + "Error enabling buffer sampling" ); + callback = new Callback; + COERRORMACRO( sampleGrabber->SetCallBack( callback, 0 ), Error, , + "Error setting callback interface for grabbing" ); + ComPtr< IPin > grabberIn = getPin( grabberBase.get(), PINDIR_INPUT, 0 ); + ERRORMACRO( grabberIn.get() != NULL, Error, , + "Error getting input of sample grabber" ); + ComPtr< IPin > grabberOut = getPin( grabberBase.get(), PINDIR_OUTPUT, 0 ); + ERRORMACRO( grabberOut.get() != NULL, Error, , + "Error getting output of sample grabber" ); + + ComPtr< IBaseFilter > nullRenderer; + COERRORMACRO( CoCreateInstance( CLSID_NullRenderer, NULL, + CLSCTX_INPROC, IID_IBaseFilter, + (void **)&nullRenderer ), + Error, , "Error creating Null Renderer" ); + COERRORMACRO( graphBuilder->AddFilter( nullRenderer.get(), L"Sink" ), + Error, , "Error adding null renderer to filter graph" ); + ComPtr< IPin > nullIn = getPin( nullRenderer.get(), PINDIR_INPUT, 0 ); + + cerr << endl << "Attempting to connect" << endl; + COERRORMACRO( graphBuilder->Connect( sourceOut.get(), grabberIn.get() ), + Error, , "Error connecting source to sample grabber" ); + COERRORMACRO( graphBuilder->Connect( grabberOut.get(), nullIn.get() ), + Error, , "Error connecting sample grabber to sink" ); + + cerr << "Success!!!!!!!!!!!!!!!!!!!!!" << endl; + + ComPtr< IMediaControl > mediaControl; + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaControl, + (void **)&mediaControl ), + Error, , "Error requesting media control interface" ); + COERRORMACRO( mediaControl->Run(), Error, , "Error running graph" ); + + ComPtr< IMediaEvent > mediaEvent; + COERRORMACRO( graphBuilder->QueryInterface( IID_IMediaEvent, + (void **)&mediaEvent ), + Error, , "Error requesting event interface" ); + + cin.get(); + + mediaControl->Stop(); + + long evCode = 0; + mediaEvent->WaitForCompletion( INFINITE, &evCode ); + + // sourceOut.reset(); + // sinkIn.reset(); + // source.reset(); + } catch ( Error &e ) { + cerr << e.what() << endl; + retVal = 1; + }; + if ( callback != NULL ) callback->Release(); + if ( initialized ) CoUninitialize(); + return retVal; +} + + + +typedef struct DscapState{ + int devid; + MSVideoSize vsize; + queue_t rq; + ms_mutex_t mutex; + int frame_ind; + int frame_max; + float fps; + float start_time; + int frame_count; + MSPixFmt fmt; +} DscapState; + + +static void dscap_init(MSFilter *f){ + DscapState *s=(DscapState *)ms_new0(DscapState,1); + s->vsize.width=MS_VIDEO_SIZE_CIF_W; + s->vsize.height=MS_VIDEO_SIZE_CIF_H; + qinit(&s->rq); + ms_mutex_init(&s->mutex,NULL); + s->start_time=0; + s->frame_count=-1; + s->fps=15; + s->fmt=MS_YUV420P; + f->data=s; +} + + + +static void dscap_uninit(MSFilter *f){ + DscapState *s=(DscapState*)f->data; + flushq(&s->rq,0); + ms_mutex_destroy(&s->mutex); + ms_free(s); +} + +static void dscap_callback(void *data, mblk_t *m){ + DscapState *s=(DscapState*)data; + ms_mutex_lock(&s->mutex); + putq(&s->rq,m); + ms_mutex_unlock(&s->mutex); +} + +static void dscap_preprocess(MSFilter * obj){ + DscapState *s=(DscapState*)obj->data; +} + +static void dscap_postprocess(MSFilter * obj){ + DscapState *s=(DscapState*)obj->data; + flushq(&s->rq,0); +} + +static void dscap_process(MSFilter * obj){ + DscapState *s=(DscapState*)obj->data; + mblk_t *m; + uint32_t timestamp; + int cur_frame; + + if (s->frame_count==-1){ + s->start_time=(float)obj->ticker->time; + s->frame_count=0; + } + + cur_frame=(int)((obj->ticker->time-s->start_time)*s->fps/1000.0); + if (cur_frame>s->frame_count){ + mblk_t *om=NULL; + /*keep the most recent frame if several frames have been captured */ + if (0){ + ms_mutex_lock(&s->mutex); + while((m=getq(&s->rq))!=NULL){ + ms_mutex_unlock(&s->mutex); + if (om!=NULL) freemsg(om); + om=m; + ms_mutex_lock(&s->mutex); + } + ms_mutex_unlock(&s->mutex); + } + if (om!=NULL){ + timestamp=(uint32_t)(obj->ticker->time*90);/* rtp uses a 90000 Hz clockrate for video*/ + mblk_set_timestamp_info(om,timestamp); + ms_queue_put(obj->outputs[0],om); + } + s->frame_count++; + } +} + +static int dscap_set_fps(MSFilter *f, void *arg){ + DscapState *s=(DscapState*)f->data; + s->fps=*((float*)arg); + return 0; +} + +static int dscap_get_pix_fmt(MSFilter *f,void *arg){ + DscapState *s=(DscapState*)f->data; + *((MSPixFmt*)arg)=s->fmt; + return 0; +} + +static int dscap_set_vsize(MSFilter *f, void *arg){ + DscapState *s=(DscapState*)f->data; + s->vsize=*((MSVideoSize*)arg); + return 0; +} + +static int dscap_get_vsize(MSFilter *f, void *arg){ + DscapState *s=(DscapState*)f->data; + MSVideoSize *vs=(MSVideoSize*)arg; + *vs=s->vsize; + return 0; +} + +static MSFilterMethod methods[]={ + { MS_FILTER_SET_FPS , dscap_set_fps }, + { MS_FILTER_GET_PIX_FMT , dscap_get_pix_fmt }, + { MS_FILTER_SET_VIDEO_SIZE, dscap_set_vsize }, + { MS_FILTER_GET_VIDEO_SIZE, dscap_get_vsize }, + { 0 , NULL } +}; + +MSFilterDesc ms_dscap_desc={ + MS_FILTER_PLUGIN_ID, + "MSDsCap", + N_("A webcam grabber based on directshow."), + MS_FILTER_OTHER, + NULL, + 0, + 1, + dscap_init, + dscap_preprocess, + dscap_process, + dscap_postprocess, + dscap_uninit, + methods +}; + + +static void ms_dshow_detect(MSWebCamManager *obj); +static MSFilter * ms_dshow_create_reader(MSWebCam *obj){ + MSFilter *f=ms_filter_new_from_desc(&ms_dscap_desc); + DscapState *s=(DscapState*)f->data; + s->devid=(int)obj->data; + return f; +} + +static MSWebCamDesc ms_dshow_cam_desc={ + "Directshow capture", + &ms_dshow_detect, + NULL, + &ms_dshow_create_reader, + NULL +}; + +static void ms_dshow_detect(MSWebCamManager *obj){ + int i; + MSWebCam *cam; + ComPtr<IPropertyBag> pBag; + COERRORMACRO( CoInitialize(NULL), Error, , "CoInitialize failed" ); + + ComPtr< ICreateDevEnum > createDevEnum; + createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum, + IID_ICreateDevEnum, "Could not create " + "device enumerator" ); + ComPtr< IEnumMoniker > enumMoniker; + if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){ + ms_error("Fail to create class enumerator."); + return; + } + createDevEnum.reset(); + enumMoniker->Reset(); + + int index = 0; + ULONG fetched = 0; + ComPtr< IMoniker > moniker; + for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) { + VARIANT var; + if (moniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag )!=S_OK) + continue; + VariantInit(&var); + if (pBag->Read( L"FriendlyName", &var, NULL )!=S_OK) + continue; + char szName[256]; + WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,szName,256,0,0); + MSWebCam *cam=ms_web_cam_new(&ms_dshow_cam_desc); + cam->name=ms_strdup(szName); + cam->data=(void*)i; + ms_web_cam_manager_prepend_cam(obj,cam); + VariantClear(&var); + } + enumMoniker.reset(); +} + +extern "C" void libmsdscap_init(void){ + ms_web_cam_manager_register_desc(ms_web_cam_manager_get(),&ms_dshow_cam_desc); +}