1
/* msdscap-mingw - mediastreamer2 plugin for video capture using directshow
2
Unlike winvideods.c filter, the following source code compiles with mingw.
3
winvideods.c requires visual studio to build.
5
Copyright (C) 2009 Simon Morlat
7
This program is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 3 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
21
This plugin has been written by Simon Morlat based on the work made by
22
Jan Wedekind, posted on mingw tracker here:
23
http://sourceforge.net/tracker/index.php?func=detail&aid=1819367&group_id=2435&atid=302435
24
He wrote all the declarations missing to get directshow capture working
25
with mingw, and provided a demo code that worked great with minimal code.
36
#include <mediastreamer2/mswebcam.h>
37
#include <mediastreamer2/msfilter.h>
38
#include <mediastreamer2/msticker.h>
39
#include <mediastreamer2/msvideo.h>
41
template <typename _ComT>
46
int coCreateInstance(REFCLSID clsid, REFIID iid){
48
res=::CoCreateInstance(clsid,NULL,CLSCTX_INPROC,iid,
50
return (res==S_OK) ? 0 : -1;
57
ComPtr(const ComPtr<_ComT>& other) : mPtr(other.mPtr){
58
if (mPtr) mPtr->AddRef();
60
ComPtr<_ComT> & operator=(const ComPtr<_ComT> &other){
68
bool operator==(const ComPtr<_ComT> &other){
69
return other.mPtr==mPtr;
71
bool operator!=(const ComPtr<_ComT> &other){
72
return other.mPtr!=mPtr;
92
DEFINE_GUID( CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01,
93
0x11d0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
94
DEFINE_GUID( CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0,
95
0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
96
DEFINE_GUID( CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce,
97
0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
98
DEFINE_GUID( CLSID_SampleGrabber, 0xc1f400a0, 0x3f08, 0x11d3,
99
0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 );
100
DEFINE_GUID( CLSID_NullRenderer,0xc1f400a4, 0x3f08, 0x11d3,
101
0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 );
102
DEFINE_GUID( CLSID_VfwCapture, 0x1b544c22, 0xfd0b, 0x11ce,
103
0x8c, 0x63, 0x0, 0xaa, 0x00, 0x44, 0xb5, 0x1e);
104
DEFINE_GUID( IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce,
105
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
106
DEFINE_GUID( IID_IBaseFilter, 0x56a86895, 0x0ad4, 0x11ce,
107
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
108
DEFINE_GUID( IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0,
109
0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 );
110
DEFINE_GUID( IID_IEnumFilters, 0x56a86893, 0xad4, 0x11ce,
111
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
112
DEFINE_GUID( IID_IEnumPins, 0x56a86892, 0x0ad4, 0x11ce,
113
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
114
DEFINE_GUID( IID_IMediaSample, 0x56a8689a, 0x0ad4, 0x11ce,
115
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
116
DEFINE_GUID( IID_IMediaFilter, 0x56a86899, 0x0ad4, 0x11ce,
117
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
118
DEFINE_GUID( IID_IPin, 0x56a86891, 0x0ad4, 0x11ce,
119
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
120
DEFINE_GUID( IID_ISampleGrabber, 0x6b652fff, 0x11fe, 0x4fce,
121
0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f );
122
DEFINE_GUID( IID_ISampleGrabberCB, 0x0579154a, 0x2b53, 0x4994,
123
0xb0, 0xd0, 0xe7, 0x73, 0x14, 0x8e, 0xff, 0x85 );
124
DEFINE_GUID( IID_IMediaEvent, 0x56a868b6, 0x0ad4, 0x11ce,
125
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
126
DEFINE_GUID( IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce,
127
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
128
DEFINE_GUID( IID_IMemInputPin, 0x56a8689d, 0x0ad4, 0x11ce,
129
0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
130
DEFINE_GUID( IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0,
131
0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56 );
132
DEFINE_GUID( IID_IVideoProcAmp, 0x4050560e, 0x42a7, 0x413a,
133
0x85, 0xc2, 0x09, 0x26, 0x9a, 0x2d, 0x0f, 0x44 );
134
DEFINE_GUID( MEDIATYPE_Video, 0x73646976, 0x0000, 0x0010,
135
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
136
DEFINE_GUID( MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010,
137
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
138
DEFINE_GUID( MEDIASUBTYPE_YV12, 0x32315659, 0x0000, 0x0010,
139
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
140
DEFINE_GUID( MEDIASUBTYPE_IYUV, 0x56555949, 0x0000, 0x0010,
141
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
142
DEFINE_GUID( MEDIASUBTYPE_YUYV, 0x56595559, 0x0000, 0x0010,
143
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
144
DEFINE_GUID( MEDIASUBTYPE_YUY2, 0x32595559, 0x0000, 0x0010,
145
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
146
DEFINE_GUID( MEDIASUBTYPE_UYVY, 0x59565955, 0x0000, 0x0010,
147
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
148
DEFINE_GUID( MEDIASUBTYPE_RGB24, 0xe436eb7d, 0x524f, 0x11ce,
149
0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
153
typedef LONGLONG REFERENCE_TIME;
155
typedef struct tagVIDEOINFOHEADER {
159
DWORD dwBitErrorRate;
160
REFERENCE_TIME AvgTimePerFrame;
161
BITMAPINFOHEADER bmiHeader;
164
typedef struct _AMMediaType {
167
BOOL bFixedSizeSamples;
168
BOOL bTemporalCompression;
176
DECLARE_ENUMERATOR_(IEnumMediaTypes,AM_MEDIA_TYPE*);
178
typedef struct _VIDEO_STREAM_CONFIG_CAPS
183
SIZE MinCroppingSize;
184
SIZE MaxCroppingSize;
185
int CropGranularityX;
186
int CropGranularityY;
191
int OutputGranularityX;
192
int OutputGranularityY;
197
LONGLONG MinFrameInterval;
198
LONGLONG MaxFrameInterval;
199
LONG MinBitsPerSecond;
200
LONG MaxBitsPerSecond;
201
} VIDEO_STREAM_CONFIG_CAPS;
203
typedef LONGLONG REFERENCE_TIME;
205
typedef interface IBaseFilter IBaseFilter;
206
typedef interface IReferenceClock IReferenceClock;
207
typedef interface IFilterGraph IFilterGraph;
209
typedef enum _FilterState {
215
#define MAX_FILTER_NAME 128
216
typedef struct _FilterInfo {
217
WCHAR achName[MAX_FILTER_NAME];
218
IFilterGraph *pGraph;
221
typedef enum _PinDirection {
226
#define MAX_PIN_NAME 128
227
typedef struct _PinInfo {
228
IBaseFilter *pFilter;
230
WCHAR achName[MAX_PIN_NAME];
233
#define INTERFACE IPin
234
DECLARE_INTERFACE_(IPin,IUnknown)
236
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
237
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
238
STDMETHOD_(ULONG,Release)(THIS) PURE;
239
STDMETHOD(Connect)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE;
240
STDMETHOD(ReceiveConnection)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE;
241
STDMETHOD(Disconnect)(THIS) PURE;
242
STDMETHOD(ConnectedTo)(THIS_ IPin**) PURE;
243
STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE*) PURE;
244
STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO*) PURE;
245
STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION*) PURE;
249
DECLARE_ENUMERATOR_(IEnumPins,IPin*);
251
typedef struct _AllocatorProperties {
256
} ALLOCATOR_PROPERTIES;
258
typedef LONG_PTR OAEVENT;
260
#define INTERFACE IMediaEvent
261
DECLARE_INTERFACE_(IMediaEvent,IDispatch)
263
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
264
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
265
STDMETHOD_(ULONG,Release)(THIS) PURE;
266
STDMETHOD(GetEventHandle)(THIS_ OAEVENT*) PURE;
267
STDMETHOD(GetEvent)(THIS_ long*,LONG_PTR,LONG_PTR,long) PURE;
268
STDMETHOD(WaitForCompletion)(THIS_ long,long*) PURE;
269
STDMETHOD(CancelDefaultHandling)(THIS_ long) PURE;
270
STDMETHOD(RestoreDefaultHandling)(THIS_ long) PURE;
271
STDMETHOD(FreeEventParams)(THIS_ long,LONG_PTR,LONG_PTR) PURE;
275
typedef long OAFilterState;
277
#define INTERFACE IMediaControl
278
DECLARE_INTERFACE_(IMediaControl,IDispatch)
280
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
281
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
282
STDMETHOD_(ULONG,Release)(THIS) PURE;
283
STDMETHOD(Run)(THIS) PURE;
284
STDMETHOD(Pause)(THIS) PURE;
285
STDMETHOD(Stop)(THIS) PURE;
286
STDMETHOD(GetState)(THIS_ LONG,OAFilterState*) PURE;
287
STDMETHOD(RenderFile)(THIS_ BSTR) PURE;
288
STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**) PURE;
289
STDMETHOD(get_FilterCollection)(THIS_ IDispatch**) PURE;
290
STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**) PURE;
291
STDMETHOD(StopWhenReady)(THIS) PURE;
295
#define INTERFACE IVideoProcAmp
296
DECLARE_INTERFACE_(IVideoProcAmp,IUnknown)
298
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
299
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
300
STDMETHOD_(ULONG,Release)(THIS) PURE;
304
#define INTERFACE IAMStreamConfig
305
DECLARE_INTERFACE_(IAMStreamConfig,IUnknown)
307
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
308
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
309
STDMETHOD_(ULONG,Release)(THIS) PURE;
310
STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE;
311
STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE;
312
STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE;
313
STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE;
317
#define INTERFACE IMediaFilter
318
DECLARE_INTERFACE_(IMediaFilter,IPersist)
320
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
321
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
322
STDMETHOD_(ULONG,Release)(THIS) PURE;
323
STDMETHOD(Stop)(THIS) PURE;
324
STDMETHOD(Pause)(THIS) PURE;
325
STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
326
STDMETHOD(GetState)(THIS_ DWORD,FILTER_STATE*) PURE;
327
STDMETHOD(SetSyncSource)(THIS_ IReferenceClock*) PURE;
328
STDMETHOD(GetSyncSource)(THIS_ IReferenceClock**) PURE;
332
#define INTERFACE IBaseFilter
333
DECLARE_INTERFACE_(IBaseFilter,IMediaFilter)
335
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
336
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
337
STDMETHOD_(ULONG,Release)(THIS) PURE;
338
STDMETHOD(EnumPins)(THIS_ IEnumPins**) PURE;
339
STDMETHOD(FindPin)(THIS_ LPCWSTR,IPin**) PURE;
340
STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO*) PURE;
341
STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph*,LPCWSTR) PURE;
342
STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR*) PURE;
346
DECLARE_ENUMERATOR_(IEnumFilters,IBaseFilter*);
348
// #define INTERFACE IEnumFilters
349
// DECLARE_INTERFACE_(IEnumFilters,IUnknown)
351
// STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
352
// STDMETHOD_(ULONG,AddRef)(THIS) PURE;
353
// STDMETHOD_(ULONG,Release)(THIS) PURE;
354
// STDMETHOD(Next)(THIS_ ULONG,IBaseFilter**,ULONG*) PURE;
355
// STDMETHOD(Skip)(THIS_ ULONG) PURE;
356
// STDMETHOD(Reset)(THIS) PURE;
357
// STDMETHOD(Clone)(THIS_ IEnumFilters**) PURE;
361
#define INTERFACE IFilterGraph
362
DECLARE_INTERFACE_(IFilterGraph,IUnknown)
364
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
365
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
366
STDMETHOD_(ULONG,Release)(THIS) PURE;
367
STDMETHOD(AddFilter)(THIS_ IBaseFilter*,LPCWSTR) PURE;
368
STDMETHOD(RemoveFilter)(THIS_ IBaseFilter*) PURE;
369
STDMETHOD(EnumFilters)(THIS_ IEnumFilters**) PURE;
370
STDMETHOD(FindFilterByName)(THIS_ LPCWSTR,IBaseFilter**) PURE;
371
STDMETHOD(ConnectDirect)(THIS_ IPin*,IPin*,const AM_MEDIA_TYPE*) PURE;
372
STDMETHOD(Reconnect)(THIS_ IPin*) PURE;
373
STDMETHOD(Disconnect)(THIS_ IPin*) PURE;
374
STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
378
#define INTERFACE IGraphBuilder
379
DECLARE_INTERFACE_(IGraphBuilder,IFilterGraph)
381
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
382
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
383
STDMETHOD_(ULONG,Release)(THIS) PURE;
384
STDMETHOD(Connect)(THIS_ IPin*,IPin*) PURE;
385
STDMETHOD(Render)(THIS_ IPin*) PURE;
386
STDMETHOD(RenderFile)(THIS_ LPCWSTR,LPCWSTR) PURE;
387
STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR,LPCWSTR,IBaseFilter**) PURE;
388
STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE;
389
STDMETHOD(Abort)(THIS) PURE;
390
STDMETHOD(ShouldOperationContinue)(THIS) PURE;
394
#define INTERFACE ICreateDevEnum
395
DECLARE_INTERFACE_(ICreateDevEnum,IUnknown)
397
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
398
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
399
STDMETHOD_(ULONG,Release)(THIS) PURE;
400
STDMETHOD(CreateClassEnumerator)(THIS_ REFIID,IEnumMoniker**,DWORD) PURE;
404
#define INTERFACE IMediaSample
405
DECLARE_INTERFACE_(IMediaSample,IUnknown)
407
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
408
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
409
STDMETHOD_(ULONG,Release)(THIS) PURE;
410
STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
411
STDMETHOD_(long, GetSize)(THIS) PURE;
414
#define INTERFACE IMediaSample
415
DECLARE_INTERFACE_(IMediaSample, IUnknown)
417
STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
418
STDMETHOD_(long, GetSize)(THIS) PURE;
419
STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
420
STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
421
STDMETHOD(IsSyncPoint)(THIS) PURE;
422
STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE;
423
STDMETHOD(IsPreroll)(THIS) PURE;
424
STDMETHOD(SetPreroll)(THIS_ BOOL) PURE;
425
STDMETHOD_(long, GetActualDataLength)(THIS) PURE;
426
STDMETHOD(SetActualDataLength)(THIS_ long) PURE;
427
STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE;
428
STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
429
STDMETHOD(IsDiscontinuity)(THIS) PURE;
430
STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE;
431
STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
432
STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
439
#define INTERFACE IMemAllocator
440
DECLARE_INTERFACE_(IMemAllocator,IUnknown)
442
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
443
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
444
STDMETHOD_(ULONG,Release)(THIS) PURE;
445
STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES*,ALLOCATOR_PROPERTIES*) PURE;
446
STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES*) PURE;
447
STDMETHOD(Commit)(THIS) PURE;
448
STDMETHOD(Decommit)(THIS) PURE;
449
STDMETHOD(GetBuffer)(THIS_ IMediaSample **,REFERENCE_TIME*,REFERENCE_TIME*,DWORD) PURE;
450
STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample*) PURE;
454
#define INTERFACE IMemInputPin
455
DECLARE_INTERFACE_(IMemInputPin,IUnknown)
457
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
458
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
459
STDMETHOD_(ULONG,Release)(THIS) PURE;
460
STDMETHOD(GetAllocator)(THIS_ IMemAllocator**) PURE;
461
STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator*,BOOL) PURE;
462
STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES*) PURE;
463
STDMETHOD(Receive)(THIS_ IMediaSample*) PURE;
464
STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample**,LONG,LONG*) PURE;
465
STDMETHOD(ReceiveCanBlock)(THIS) PURE;
469
#define INTERFACE ISampleGrabberCB
470
DECLARE_INTERFACE_(ISampleGrabberCB,IUnknown)
472
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
473
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
474
STDMETHOD_(ULONG,Release)(THIS) PURE;
475
STDMETHOD(SampleCB)(THIS_ double,IMediaSample*) PURE;
476
STDMETHOD(BufferCB)(THIS_ double,BYTE*,long) PURE;
480
#define INTERFACE ISampleGrabber
481
DECLARE_INTERFACE_(ISampleGrabber,IUnknown)
483
STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
484
STDMETHOD_(ULONG,AddRef)(THIS) PURE;
485
STDMETHOD_(ULONG,Release)(THIS) PURE;
486
STDMETHOD(SetOneShot)(THIS_ BOOL) PURE;
487
STDMETHOD(SetMediaType)(THIS_ const AM_MEDIA_TYPE*) PURE;
488
STDMETHOD(GetConnectedMediaType)(THIS_ AM_MEDIA_TYPE*) PURE;
489
STDMETHOD(SetBufferSamples)(THIS_ BOOL) PURE;
490
STDMETHOD(GetCurrentBuffer)(THIS_ long*,long*) PURE;
491
STDMETHOD(GetCurrentSample)(THIS_ IMediaSample**) PURE;
492
STDMETHOD(SetCallBack)(THIS_ ISampleGrabberCB *,long) PURE;
496
ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num )
498
ComPtr< IPin > retVal;
499
ComPtr< IEnumPins > enumPins;
500
if (filter->EnumPins( &enumPins )!=S_OK){
501
ms_error("Error getting pin enumerator" );
506
while ( enumPins->Next( 1, &pin, &found ) == S_OK ) {
507
PIN_DIRECTION pinDirection = (PIN_DIRECTION)( -1 );
508
pin->QueryDirection( &pinDirection );
509
if ( pinDirection == direction ) {
522
class DSCapture : public ISampleGrabberCB{
526
ms_mutex_init(&_mutex,NULL);
527
_vsize=MS_VIDEO_SIZE_CIF;
535
virtual ~DSCapture(){
536
if (_ready) stopAndClean();
538
ms_mutex_destroy(&_mutex);
540
STDMETHODIMP QueryInterface( REFIID riid, void **ppv );
541
STDMETHODIMP_(ULONG) AddRef(void);
542
STDMETHODIMP_(ULONG) Release(void);
543
STDMETHODIMP SampleCB(double,IMediaSample*);
544
STDMETHODIMP BufferCB(double,BYTE*,long);
545
int startDshowGraph();
549
ms_mutex_lock(&_mutex);
551
ms_mutex_unlock(&_mutex);
554
bool isTimeToSend(uint64_t ticker_time);
555
MSVideoSize getVSize()const{
558
void setVSize(MSVideoSize vsize){
561
void setFps(float fps){
564
MSPixFmt getPixFmt(){
565
if (!_ready) createDshowGraph(); /* so that _pixfmt is updated*/
568
void setDeviceIndex(int index){
574
int createDshowGraph();
575
int selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count);
584
ComPtr< IGraphBuilder > _graphBuilder;
585
ComPtr< IBaseFilter > _source;
586
ComPtr< IBaseFilter > _nullRenderer;
587
ComPtr< IBaseFilter > _grabberBase;
588
ComPtr< IMediaControl > _mediaControl;
589
ComPtr< IMediaEvent > _mediaEvent;
594
STDMETHODIMP DSCapture::QueryInterface(REFIID riid, void **ppv)
597
if ( ppv == NULL ) return E_POINTER;
599
if ( riid == IID_IUnknown ) {
600
*ppv = static_cast< IUnknown * >( this );
603
} else if ( riid == IID_ISampleGrabberCB ) {
604
*ppv = static_cast< ISampleGrabberCB * >( this );
608
retval = E_NOINTERFACE;
613
STDMETHODIMP_(ULONG) DSCapture::AddRef(){
618
STDMETHODIMP_(ULONG) DSCapture::Release()
620
ms_message("DSCapture::Release");
621
if ( !InterlockedDecrement( &m_refCount ) ) {
622
int refcnt=m_refCount;
629
static void dummy(void*p){
632
STDMETHODIMP DSCapture::SampleCB( double par1 , IMediaSample * sample)
636
if (sample->GetPointer(&p)!=S_OK){
637
ms_error("error in GetPointer()");
640
size=sample->GetSize();
641
//ms_message( "DSCapture::SampleCB pointer=%p, size=%i",p,size);
642
mblk_t *m=esballoc(p,size,0,dummy);
644
ms_mutex_lock(&_mutex);
646
ms_mutex_unlock(&_mutex);
652
STDMETHODIMP DSCapture::BufferCB( double, BYTE *b, long len)
654
ms_message("DSCapture::BufferCB");
658
static void dscap_init(MSFilter *f){
659
DSCapture *s=new DSCapture();
665
static void dscap_uninit(MSFilter *f){
666
DSCapture *s=(DSCapture*)f->data;
670
static char * fourcc_to_char(char *str, uint32_t fcc){
676
static int find_best_format(ComPtr<IAMStreamConfig> streamConfig, int count, MSVideoSize *requested_size, MSPixFmt requested_fmt ){
678
MSVideoSize best_found=(MSVideoSize){32768,32768};
681
char selected_fcc[5];
682
for (i=0; i<count; i++ ) {
683
VIDEO_STREAM_CONFIG_CAPS videoConfig;
684
AM_MEDIA_TYPE *mediaType;
685
if (streamConfig->GetStreamCaps( i, &mediaType,
686
(BYTE *)&videoConfig )!=S_OK){
687
ms_error( "Error getting stream capabilities");
690
if ( mediaType->majortype == MEDIATYPE_Video &&
691
mediaType->cbFormat != 0 ) {
692
VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat;
693
ms_message("Seeing format %ix%i %s",infoHeader->bmiHeader.biWidth,infoHeader->bmiHeader.biHeight,
694
fourcc_to_char(fccstr,infoHeader->bmiHeader.biCompression));
695
if (ms_fourcc_to_pix_fmt(infoHeader->bmiHeader.biCompression)==requested_fmt){
697
cur.width=infoHeader->bmiHeader.biWidth;
698
cur.height=infoHeader->bmiHeader.biHeight;
699
if (ms_video_size_greater_than(cur,*requested_size)){
700
if (ms_video_size_greater_than(best_found,cur)){
703
fourcc_to_char(selected_fcc,infoHeader->bmiHeader.biCompression);
708
if ( mediaType->cbFormat != 0 )
709
CoTaskMemFree( (PVOID)mediaType->pbFormat );
710
if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release();
711
CoTaskMemFree( (PVOID)mediaType );
713
if (best_index!=-1) {
714
*requested_size=best_found;
715
ms_message("Best camera format is %s %ix%i",selected_fcc,best_found.width,best_found.height);
720
int DSCapture::selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count){
723
index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
724
if (index!=-1) goto success;
726
index=find_best_format(streamConfig, count, &_vsize,_pixfmt);
727
if (index!=-1) goto success;
729
index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
730
if (index!=-1) goto success;
732
index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
734
_pixfmt=MS_RGB24_REV;
737
ms_error("This camera does not support any of our pixel formats.");
741
VIDEO_STREAM_CONFIG_CAPS videoConfig;
742
AM_MEDIA_TYPE *mediaType;
743
if (streamConfig->GetStreamCaps( index, &mediaType,
744
(BYTE *)&videoConfig )!=S_OK){
745
ms_error( "Error getting stream capabilities" );
747
streamConfig->SetFormat( mediaType );
751
int DSCapture::createDshowGraph(){
752
ComPtr< ICreateDevEnum > createDevEnum;
755
if (createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
756
IID_ICreateDevEnum )==-1){
757
ms_error("Could not create device enumerator");
760
ComPtr< IEnumMoniker > enumMoniker;
761
if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
762
ms_error("Fail to create class enumerator.");
765
createDevEnum.reset();
766
enumMoniker->Reset();
769
if (_graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder )!=0){
770
ms_error("Could not create graph builder.");
773
ComPtr< IMoniker > moniker;
774
for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
776
if (moniker->BindToObject( 0, 0, IID_IBaseFilter, (void **)&_source )!=S_OK){
777
ms_error("Error binding moniker to base filter" );
782
if (_source.get()==0){
783
ms_error("Could not interface with webcam devid=%i",_devid);
788
if (_graphBuilder->AddFilter( _source.get(), L"Source" )!=S_OK){
789
ms_error("Error adding camera source to filter graph" );
792
ComPtr< IPin > sourceOut = getPin( _source.get(), PINDIR_OUTPUT, 0 );
793
if (sourceOut.get()==NULL){
794
ms_error("Error getting output pin of camera source" );
797
ComPtr< IAMStreamConfig > streamConfig;
798
if (sourceOut->QueryInterface( IID_IAMStreamConfig,
799
(void **)&streamConfig )!=S_OK){
800
ms_error("Error requesting stream configuration API" );
804
if (streamConfig->GetNumberOfCapabilities( &count, &size )!=S_OK){
805
ms_error("Error getting number of capabilities" );
808
if (selectBestFormat(streamConfig,count)!=0){
811
streamConfig.reset();
813
if (CoCreateInstance( CLSID_SampleGrabber, NULL,
814
CLSCTX_INPROC, IID_IBaseFilter,
815
(void **)&_grabberBase )!=S_OK){
816
ms_error("Error creating sample grabber" );
819
if (_graphBuilder->AddFilter( _grabberBase.get(), L"Grabber" )!=S_OK){
820
ms_error("Error adding sample grabber to filter graph");
823
ComPtr< ISampleGrabber > sampleGrabber;
824
if (_grabberBase->QueryInterface( IID_ISampleGrabber,
825
(void **)&sampleGrabber )!=S_OK){
826
ms_error("Error requesting sample grabber interface");
829
if (sampleGrabber->SetOneShot( FALSE )!=S_OK){
830
ms_error("Error disabling one-shot mode" );
833
if (sampleGrabber->SetBufferSamples( TRUE )!=S_OK){
834
ms_error("Error enabling buffer sampling" );
837
if (sampleGrabber->SetCallBack(this, 0 )!=S_OK){
838
ms_error("Error setting callback interface for grabbing" );
841
ComPtr< IPin > grabberIn = getPin( _grabberBase.get(), PINDIR_INPUT, 0 );
842
if (grabberIn.get() == NULL){
843
ms_error("Error getting input of sample grabber");
846
ComPtr< IPin > grabberOut = getPin( _grabberBase.get(), PINDIR_OUTPUT, 0 );
847
if (grabberOut.get()==NULL){
848
ms_error("Error getting output of sample grabber" );
851
if (CoCreateInstance( CLSID_NullRenderer, NULL,
852
CLSCTX_INPROC, IID_IBaseFilter,
853
(void **)&_nullRenderer )!=S_OK){
854
ms_error("Error creating Null Renderer" );
857
if (_graphBuilder->AddFilter( _nullRenderer.get(), L"Sink" )!=S_OK){
858
ms_error("Error adding null renderer to filter graph" );
861
ComPtr< IPin > nullIn = getPin( _nullRenderer.get(), PINDIR_INPUT, 0 );
862
if (_graphBuilder->Connect( sourceOut.get(), grabberIn.get() )!=S_OK){
863
ms_error("Error connecting source to sample grabber" );
866
if (_graphBuilder->Connect( grabberOut.get(), nullIn.get() )!=S_OK){
867
ms_error("Error connecting sample grabber to sink" );
870
ms_message("Directshow graph is now ready to run.");
872
if (_graphBuilder->QueryInterface( IID_IMediaControl,
873
(void **)&_mediaControl )!=S_OK){
874
ms_error("Error requesting media control interface" );
877
if (_graphBuilder->QueryInterface( IID_IMediaEvent,
878
(void **)&_mediaEvent )!=S_OK){
879
ms_error("Error requesting event interface" );
886
int DSCapture::startDshowGraph(){
888
if (createDshowGraph()!=0) return -1;
890
HRESULT r=_mediaControl->Run();
891
if (r!=S_OK && r!=S_FALSE){
892
ms_error("Error starting graph (%i)",r);
895
ms_message("Graph started");
899
void DSCapture::stopAndClean(){
900
if (_mediaControl.get()!=NULL){
902
r=_mediaControl->Stop();
904
ms_error("msdscap: Could not stop graph !");
907
_graphBuilder->RemoveFilter(_source.get());
908
_graphBuilder->RemoveFilter(_grabberBase.get());
909
_graphBuilder->RemoveFilter(_nullRenderer.get());
912
_grabberBase.reset();
913
_nullRenderer.reset();
914
_mediaControl.reset();
916
_graphBuilder.reset();
918
ms_mutex_lock(&_mutex);
920
ms_mutex_unlock(&_mutex);
924
bool DSCapture::isTimeToSend(uint64_t ticker_time){
925
if (_frame_count==-1){
926
_start_time=(float)ticker_time;
929
int cur_frame=(int)(((float)ticker_time-_start_time)*_fps/1000.0);
930
if (cur_frame>_frame_count){
937
static void dscap_preprocess(MSFilter * obj){
938
DSCapture *s=(DSCapture*)obj->data;
939
s->startDshowGraph();
942
static void dscap_postprocess(MSFilter * obj){
943
DSCapture *s=(DSCapture*)obj->data;
947
static void dscap_process(MSFilter * obj){
948
DSCapture *s=(DSCapture*)obj->data;
952
if (s->isTimeToSend(obj->ticker->time)){
954
/*keep the most recent frame if several frames have been captured */
955
while((m=s->readFrame())!=NULL){
956
if (om!=NULL) freemsg(om);
960
timestamp=(uint32_t)(obj->ticker->time*90);/* rtp uses a 90000 Hz clockrate for video*/
961
mblk_set_timestamp_info(om,timestamp);
962
ms_queue_put(obj->outputs[0],om);
967
static int dscap_set_fps(MSFilter *f, void *arg){
968
DSCapture *s=(DSCapture*)f->data;
969
s->setFps(*(float*)arg);
973
static int dscap_get_pix_fmt(MSFilter *f,void *arg){
974
DSCapture *s=(DSCapture*)f->data;
975
*((MSPixFmt*)arg)=s->getPixFmt();
979
static int dscap_set_vsize(MSFilter *f, void *arg){
980
DSCapture *s=(DSCapture*)f->data;
981
s->setVSize(*((MSVideoSize*)arg));
985
static int dscap_get_vsize(MSFilter *f, void *arg){
986
DSCapture *s=(DSCapture*)f->data;
987
MSVideoSize *vs=(MSVideoSize*)arg;
992
static MSFilterMethod methods[]={
993
{ MS_FILTER_SET_FPS , dscap_set_fps },
994
{ MS_FILTER_GET_PIX_FMT , dscap_get_pix_fmt },
995
{ MS_FILTER_SET_VIDEO_SIZE, dscap_set_vsize },
996
{ MS_FILTER_GET_VIDEO_SIZE, dscap_get_vsize },
1000
MSFilterDesc ms_dscap_desc={
1003
N_("A webcam grabber based on directshow."),
1017
static void ms_dshow_detect(MSWebCamManager *obj);
1018
static MSFilter * ms_dshow_create_reader(MSWebCam *obj){
1019
MSFilter *f=ms_filter_new_from_desc(&ms_dscap_desc);
1020
DSCapture *s=(DSCapture*)f->data;
1021
s->setDeviceIndex((int)obj->data);
1025
MSWebCamDesc ms_dshow_cam_desc={
1026
"Directshow capture",
1029
&ms_dshow_create_reader,
1033
static void ms_dshow_detect(MSWebCamManager *obj){
1034
ComPtr<IPropertyBag> pBag;
1038
ComPtr< ICreateDevEnum > createDevEnum;
1039
if (createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
1040
IID_ICreateDevEnum)!=0){
1041
ms_error( "Could not create device enumerator" );
1044
ComPtr< IEnumMoniker > enumMoniker;
1045
if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
1046
ms_error("Fail to create class enumerator.");
1049
createDevEnum.reset();
1050
enumMoniker->Reset();
1053
ComPtr< IMoniker > moniker;
1054
for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
1056
if (moniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag )!=S_OK)
1059
if (pBag->Read( L"FriendlyName", &var, NULL )!=S_OK)
1062
WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,szName,256,0,0);
1063
MSWebCam *cam=ms_web_cam_new(&ms_dshow_cam_desc);
1064
cam->name=ms_strdup(szName);
1066
ms_web_cam_manager_prepend_cam(obj,cam);
1069
enumMoniker.reset();