source: mediastreamer2/linphone/mediastreamer2/plugins/msdscap/mdscap.cc @ 396:e83a54f67a91

Last change on this file since 396:e83a54f67a91 was 396:e83a54f67a91, checked in by smorlat <smorlat@…>, 4 years ago

new directshow filter works

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@399 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

  • Property exe set to *
File size: 30.8 KB
Line 
1// This is a DirectShow interface. But maybe you'll find that it's easier to
2// access the camera directly ;)
3
4// http://www.codeguru.com/cpp/g-m/multimedia/video/article.php/c9551/
5// http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2007-April/027965.html
6// http://msdn2.microsoft.com/en-us/library/ms787594.aspx
7// http://msdn2.microsoft.com/en-us/library/ms787867.aspx
8// NullRenderer wih reference clock set to NULL
9// http://www.videolan.org/
10// http://git.videolan.org/gitweb.cgi?p=vlc.git;f=modules/access/dshow;hb=0.8.6
11
12// #include <wtypes.h>
13// #include <unknwn.h>
14// #include <ole2.h>
15// #include <limits.h>
16// #include <dshow.h>
17
18#include <iostream>
19#include <iomanip>
20#include <fstream>
21#include <windows.h>
22#include <winnls.h>
23#include <errors.h>
24#include <initguid.h>
25#include <ocidl.h>
26#include <malloc.h>
27#include "comptr.hh"
28#include "error.hh"
29
30#include <mediastreamer2/mswebcam.h>
31#include <mediastreamer2/msfilter.h>
32#include <mediastreamer2/msticker.h>
33#include <mediastreamer2/msvideo.h>
34
35#define FILTER_NAME L"HornetsEye Capture Filter"
36#define PIN_NAME L"Capture"
37
38using namespace Hornetseye;
39
40DEFINE_GUID( CLSID_VideoInputDeviceCategory, 0x860BB310, 0x5D01,
41             0x11d0, 0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86);
42DEFINE_GUID( CLSID_SystemDeviceEnum, 0x62BE5D10, 0x60EB, 0x11d0,
43             0xBD, 0x3B, 0x00, 0xA0, 0xC9, 0x11, 0xCE, 0x86 );
44DEFINE_GUID( CLSID_FilterGraph, 0xe436ebb3, 0x524f, 0x11ce,
45             0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
46DEFINE_GUID( CLSID_SampleGrabber, 0xc1f400a0, 0x3f08, 0x11d3,
47             0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 );
48DEFINE_GUID( CLSID_NullRenderer,0xc1f400a4, 0x3f08, 0x11d3,
49             0x9f, 0x0b, 0x00, 0x60, 0x08, 0x03, 0x9e, 0x37 );
50DEFINE_GUID( CLSID_VfwCapture, 0x1b544c22, 0xfd0b, 0x11ce,
51             0x8c, 0x63, 0x0, 0xaa, 0x00, 0x44, 0xb5, 0x1e);
52DEFINE_GUID( IID_IGraphBuilder, 0x56a868a9, 0x0ad4, 0x11ce,
53             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70);
54DEFINE_GUID( IID_IBaseFilter, 0x56a86895, 0x0ad4, 0x11ce,
55             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
56DEFINE_GUID( IID_ICreateDevEnum, 0x29840822, 0x5b84, 0x11d0,
57             0xbd, 0x3b, 0x00, 0xa0, 0xc9, 0x11, 0xce, 0x86 );
58DEFINE_GUID( IID_IEnumFilters, 0x56a86893, 0xad4, 0x11ce,
59             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
60DEFINE_GUID( IID_IEnumPins, 0x56a86892, 0x0ad4, 0x11ce,
61             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
62DEFINE_GUID( IID_IMediaSample, 0x56a8689a, 0x0ad4, 0x11ce,
63             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
64DEFINE_GUID( IID_IMediaFilter, 0x56a86899, 0x0ad4, 0x11ce,
65             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
66DEFINE_GUID( IID_IPin, 0x56a86891, 0x0ad4, 0x11ce,
67             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
68DEFINE_GUID( IID_ISampleGrabber, 0x6b652fff, 0x11fe, 0x4fce,
69             0x92, 0xad, 0x02, 0x66, 0xb5, 0xd7, 0xc7, 0x8f );
70DEFINE_GUID( IID_ISampleGrabberCB, 0x0579154a, 0x2b53, 0x4994,
71             0xb0, 0xd0, 0xe7, 0x73, 0x14, 0x8e, 0xff, 0x85 );
72DEFINE_GUID( IID_IMediaEvent, 0x56a868b6, 0x0ad4, 0x11ce,
73             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
74DEFINE_GUID( IID_IMediaControl, 0x56a868b1, 0x0ad4, 0x11ce,
75             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
76DEFINE_GUID( IID_IMemInputPin, 0x56a8689d, 0x0ad4, 0x11ce,
77             0xb0, 0x3a, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
78DEFINE_GUID( IID_IAMStreamConfig, 0xc6e13340, 0x30ac, 0x11d0,
79             0xa1, 0x8c, 0x00, 0xa0, 0xc9, 0x11, 0x89, 0x56 );
80DEFINE_GUID( IID_IVideoProcAmp, 0x4050560e, 0x42a7, 0x413a,
81             0x85, 0xc2, 0x09, 0x26, 0x9a, 0x2d, 0x0f, 0x44 );
82DEFINE_GUID( MEDIATYPE_Video, 0x73646976, 0x0000, 0x0010,
83             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
84DEFINE_GUID( MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010,
85             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
86DEFINE_GUID( MEDIASUBTYPE_YV12, 0x32315659, 0x0000, 0x0010,
87             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
88DEFINE_GUID( MEDIASUBTYPE_IYUV, 0x56555949, 0x0000, 0x0010,
89             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
90DEFINE_GUID( MEDIASUBTYPE_YUYV, 0x56595559, 0x0000, 0x0010,
91             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
92DEFINE_GUID( MEDIASUBTYPE_YUY2, 0x32595559, 0x0000, 0x0010,
93             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
94DEFINE_GUID( MEDIASUBTYPE_UYVY, 0x59565955, 0x0000, 0x0010,
95             0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 );
96DEFINE_GUID( MEDIASUBTYPE_RGB24, 0xe436eb7d, 0x524f, 0x11ce,
97             0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70 );
98
99using namespace std;
100
101typedef LONGLONG REFERENCE_TIME;
102
103typedef struct tagVIDEOINFOHEADER {
104  RECT rcSource;
105  RECT rcTarget;
106  DWORD dwBitRate;
107  DWORD dwBitErrorRate;
108  REFERENCE_TIME AvgTimePerFrame;
109  BITMAPINFOHEADER bmiHeader;
110} VIDEOINFOHEADER;
111
112typedef struct _AMMediaType {
113  GUID majortype;
114  GUID subtype;
115  BOOL bFixedSizeSamples;
116  BOOL bTemporalCompression;
117  ULONG lSampleSize;
118  GUID formattype;
119  IUnknown *pUnk;
120  ULONG cbFormat;
121  BYTE *pbFormat;
122} AM_MEDIA_TYPE;
123
124DECLARE_ENUMERATOR_(IEnumMediaTypes,AM_MEDIA_TYPE*);
125
126typedef struct _VIDEO_STREAM_CONFIG_CAPS
127{
128  GUID guid;
129  ULONG VideoStandard;
130  SIZE InputSize;
131  SIZE MinCroppingSize;
132  SIZE MaxCroppingSize;
133  int CropGranularityX;
134  int CropGranularityY;
135  int CropAlignX;
136  int CropAlignY;
137  SIZE MinOutputSize;
138  SIZE MaxOutputSize;
139  int OutputGranularityX;
140  int OutputGranularityY;
141  int StretchTapsX;
142  int StretchTapsY;
143  int ShrinkTapsX;
144  int ShrinkTapsY;
145  LONGLONG MinFrameInterval;
146  LONGLONG MaxFrameInterval;
147  LONG MinBitsPerSecond;
148  LONG MaxBitsPerSecond;
149} VIDEO_STREAM_CONFIG_CAPS;
150
151typedef LONGLONG REFERENCE_TIME;
152
153typedef interface IBaseFilter IBaseFilter;
154typedef interface IReferenceClock IReferenceClock;
155typedef interface IFilterGraph IFilterGraph;
156
157typedef enum _FilterState {
158  State_Stopped,
159  State_Paused,
160  State_Running
161} FILTER_STATE;
162
163#define MAX_FILTER_NAME 128
164typedef struct _FilterInfo {
165  WCHAR achName[MAX_FILTER_NAME]; 
166  IFilterGraph *pGraph;
167} FILTER_INFO;
168
169typedef enum _PinDirection {
170  PINDIR_INPUT,
171  PINDIR_OUTPUT
172} PIN_DIRECTION;
173
174#define MAX_PIN_NAME 128
175typedef struct _PinInfo {
176  IBaseFilter *pFilter;
177  PIN_DIRECTION dir;
178  WCHAR achName[MAX_PIN_NAME];
179} PIN_INFO;
180
181#define INTERFACE IPin
182DECLARE_INTERFACE_(IPin,IUnknown)
183{
184  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
185  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
186  STDMETHOD_(ULONG,Release)(THIS) PURE;
187  STDMETHOD(Connect)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE;
188  STDMETHOD(ReceiveConnection)(THIS_ IPin*,const AM_MEDIA_TYPE*) PURE;
189  STDMETHOD(Disconnect)(THIS) PURE;
190  STDMETHOD(ConnectedTo)(THIS_ IPin**) PURE;
191  STDMETHOD(ConnectionMediaType)(THIS_ AM_MEDIA_TYPE*) PURE;
192  STDMETHOD(QueryPinInfo)(THIS_ PIN_INFO*) PURE;
193  STDMETHOD(QueryDirection)(THIS_ PIN_DIRECTION*) PURE;
194};
195#undef INTERFACE
196
197DECLARE_ENUMERATOR_(IEnumPins,IPin*);
198
199typedef struct _AllocatorProperties {
200  long cBuffers;
201  long cbBuffer;
202  long cbAlign;
203  long cbPrefix;
204} ALLOCATOR_PROPERTIES;
205
206typedef LONG_PTR OAEVENT;
207
208#define INTERFACE IMediaEvent
209DECLARE_INTERFACE_(IMediaEvent,IDispatch)
210{
211  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
212  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
213  STDMETHOD_(ULONG,Release)(THIS) PURE;
214  STDMETHOD(GetEventHandle)(THIS_ OAEVENT*) PURE;
215  STDMETHOD(GetEvent)(THIS_ long*,LONG_PTR,LONG_PTR,long) PURE;
216  STDMETHOD(WaitForCompletion)(THIS_ long,long*) PURE;
217  STDMETHOD(CancelDefaultHandling)(THIS_ long) PURE;
218  STDMETHOD(RestoreDefaultHandling)(THIS_ long) PURE;
219  STDMETHOD(FreeEventParams)(THIS_ long,LONG_PTR,LONG_PTR) PURE;
220};
221#undef INTERFACE
222
223typedef long OAFilterState;
224
225#define INTERFACE IMediaControl
226DECLARE_INTERFACE_(IMediaControl,IDispatch)
227{
228  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
229  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
230  STDMETHOD_(ULONG,Release)(THIS) PURE;
231  STDMETHOD(Run)(THIS) PURE;
232  STDMETHOD(Pause)(THIS) PURE;
233  STDMETHOD(Stop)(THIS) PURE;
234  STDMETHOD(GetState)(THIS_ LONG,OAFilterState*) PURE;
235  STDMETHOD(RenderFile)(THIS_ BSTR) PURE;
236  STDMETHOD(AddSourceFilter)(THIS_ BSTR,IDispatch**) PURE;
237  STDMETHOD(get_FilterCollection)(THIS_ IDispatch**) PURE;
238  STDMETHOD(get_RegFilterCollection)(THIS_ IDispatch**) PURE;
239  STDMETHOD(StopWhenReady)(THIS) PURE;
240};
241#undef INTERFACE
242
243#define INTERFACE IVideoProcAmp
244DECLARE_INTERFACE_(IVideoProcAmp,IUnknown)
245{
246  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
247  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
248  STDMETHOD_(ULONG,Release)(THIS) PURE;
249};
250#undef INTERFACE
251
252#define INTERFACE IAMStreamConfig
253DECLARE_INTERFACE_(IAMStreamConfig,IUnknown)
254{
255  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
256  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
257  STDMETHOD_(ULONG,Release)(THIS) PURE;
258  STDMETHOD(SetFormat)(THIS_ AM_MEDIA_TYPE*) PURE;
259  STDMETHOD(GetFormat)(THIS_ AM_MEDIA_TYPE**) PURE;
260  STDMETHOD(GetNumberOfCapabilities)(THIS_ int*,int*) PURE;
261  STDMETHOD(GetStreamCaps)(THIS_ int,AM_MEDIA_TYPE**,BYTE*) PURE;
262};
263#undef INTERFACE
264
265#define INTERFACE IMediaFilter
266DECLARE_INTERFACE_(IMediaFilter,IPersist)
267{
268  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
269  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
270  STDMETHOD_(ULONG,Release)(THIS) PURE;
271  STDMETHOD(Stop)(THIS) PURE;
272  STDMETHOD(Pause)(THIS) PURE;
273  STDMETHOD(Run)(THIS_ REFERENCE_TIME) PURE;
274  STDMETHOD(GetState)(THIS_ DWORD,FILTER_STATE*) PURE;
275  STDMETHOD(SetSyncSource)(THIS_ IReferenceClock*) PURE;
276  STDMETHOD(GetSyncSource)(THIS_ IReferenceClock**) PURE;
277};
278#undef INTERFACE
279
280#define INTERFACE IBaseFilter
281DECLARE_INTERFACE_(IBaseFilter,IMediaFilter)
282{
283  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
284  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
285  STDMETHOD_(ULONG,Release)(THIS) PURE;
286  STDMETHOD(EnumPins)(THIS_ IEnumPins**) PURE;
287  STDMETHOD(FindPin)(THIS_ LPCWSTR,IPin**) PURE;
288  STDMETHOD(QueryFilterInfo)(THIS_ FILTER_INFO*) PURE;
289  STDMETHOD(JoinFilterGraph)(THIS_ IFilterGraph*,LPCWSTR) PURE;
290  STDMETHOD(QueryVendorInfo)(THIS_ LPWSTR*) PURE;
291};
292#undef INTERFACE
293
294DECLARE_ENUMERATOR_(IEnumFilters,IBaseFilter*);
295
296// #define INTERFACE IEnumFilters
297// DECLARE_INTERFACE_(IEnumFilters,IUnknown)
298// {
299//   STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
300//   STDMETHOD_(ULONG,AddRef)(THIS) PURE;
301//   STDMETHOD_(ULONG,Release)(THIS) PURE;
302//   STDMETHOD(Next)(THIS_ ULONG,IBaseFilter**,ULONG*) PURE;
303//   STDMETHOD(Skip)(THIS_ ULONG) PURE;
304//   STDMETHOD(Reset)(THIS) PURE;
305//   STDMETHOD(Clone)(THIS_ IEnumFilters**) PURE;
306// };
307// #undef INTERFACE
308
309#define INTERFACE IFilterGraph
310DECLARE_INTERFACE_(IFilterGraph,IUnknown)
311{
312  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
313  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
314  STDMETHOD_(ULONG,Release)(THIS) PURE;
315  STDMETHOD(AddFilter)(THIS_ IBaseFilter*,LPCWSTR) PURE;
316  STDMETHOD(RemoveFilter)(THIS_ IBaseFilter*) PURE;
317  STDMETHOD(EnumFilters)(THIS_ IEnumFilters**) PURE;
318  STDMETHOD(FindFilterByName)(THIS_ LPCWSTR,IBaseFilter**) PURE;
319  STDMETHOD(ConnectDirect)(THIS_ IPin*,IPin*,const AM_MEDIA_TYPE*) PURE;
320  STDMETHOD(Reconnect)(THIS_ IPin*) PURE;
321  STDMETHOD(Disconnect)(THIS_ IPin*) PURE;
322  STDMETHOD(SetDefaultSyncSource)(THIS) PURE;
323};
324#undef INTERFACE
325
326#define INTERFACE IGraphBuilder
327DECLARE_INTERFACE_(IGraphBuilder,IFilterGraph)
328{
329  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
330  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
331  STDMETHOD_(ULONG,Release)(THIS) PURE;
332  STDMETHOD(Connect)(THIS_ IPin*,IPin*) PURE;
333  STDMETHOD(Render)(THIS_ IPin*) PURE;
334  STDMETHOD(RenderFile)(THIS_ LPCWSTR,LPCWSTR) PURE;
335  STDMETHOD(AddSourceFilter)(THIS_ LPCWSTR,LPCWSTR,IBaseFilter**) PURE;
336  STDMETHOD(SetLogFile)(THIS_ DWORD_PTR) PURE;
337  STDMETHOD(Abort)(THIS) PURE;
338  STDMETHOD(ShouldOperationContinue)(THIS) PURE;
339};
340#undef INTERFACE
341
342#define INTERFACE ICreateDevEnum
343DECLARE_INTERFACE_(ICreateDevEnum,IUnknown)
344{
345  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
346  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
347  STDMETHOD_(ULONG,Release)(THIS) PURE;
348  STDMETHOD(CreateClassEnumerator)(THIS_ REFIID,IEnumMoniker**,DWORD) PURE;
349};
350#undef INTERFACE
351
352#define INTERFACE IMediaSample
353DECLARE_INTERFACE_(IMediaSample,IUnknown)
354{
355  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
356  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
357  STDMETHOD_(ULONG,Release)(THIS) PURE;
358  STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
359  STDMETHOD_(long, GetSize)(THIS) PURE;
360};
361/*
362#define INTERFACE IMediaSample
363DECLARE_INTERFACE_(IMediaSample, IUnknown)
364{
365    STDMETHOD(GetPointer)(THIS_ BYTE **) PURE;
366    STDMETHOD_(long, GetSize)(THIS) PURE;
367    STDMETHOD(GetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
368    STDMETHOD(SetTime)(THIS_ REFERENCE_TIME *, REFERENCE_TIME *) PURE;
369    STDMETHOD(IsSyncPoint)(THIS) PURE;
370    STDMETHOD(SetSyncPoint)(THIS_ BOOL) PURE;
371    STDMETHOD(IsPreroll)(THIS) PURE;
372    STDMETHOD(SetPreroll)(THIS_ BOOL) PURE;
373    STDMETHOD_(long, GetActualDataLength)(THIS) PURE;
374    STDMETHOD(SetActualDataLength)(THIS_ long) PURE;
375    STDMETHOD(GetMediaType)(THIS_ AM_MEDIA_TYPE **) PURE;
376    STDMETHOD(SetMediaType)(THIS_ AM_MEDIA_TYPE *) PURE;
377    STDMETHOD(IsDiscontinuity)(THIS) PURE;
378    STDMETHOD(SetDiscontinuity)(THIS_ BOOL) PURE;
379    STDMETHOD(GetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
380    STDMETHOD(SetMediaTime)(THIS_ LONGLONG *, LONGLONG *) PURE;
381};
382*/
383
384
385#undef INTERFACE
386
387#define INTERFACE IMemAllocator
388DECLARE_INTERFACE_(IMemAllocator,IUnknown)
389{
390  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
391  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
392  STDMETHOD_(ULONG,Release)(THIS) PURE;
393  STDMETHOD(SetProperties)(THIS_ ALLOCATOR_PROPERTIES*,ALLOCATOR_PROPERTIES*) PURE;
394  STDMETHOD(GetProperties)(THIS_ ALLOCATOR_PROPERTIES*) PURE;
395  STDMETHOD(Commit)(THIS) PURE;
396  STDMETHOD(Decommit)(THIS) PURE;
397  STDMETHOD(GetBuffer)(THIS_ IMediaSample **,REFERENCE_TIME*,REFERENCE_TIME*,DWORD) PURE;
398  STDMETHOD(ReleaseBuffer)(THIS_ IMediaSample*) PURE;
399};
400#undef INTERFACE
401
402#define INTERFACE IMemInputPin
403DECLARE_INTERFACE_(IMemInputPin,IUnknown)
404{
405  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
406  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
407  STDMETHOD_(ULONG,Release)(THIS) PURE;
408  STDMETHOD(GetAllocator)(THIS_ IMemAllocator**) PURE;
409  STDMETHOD(NotifyAllocator)(THIS_ IMemAllocator*,BOOL) PURE;
410  STDMETHOD(GetAllocatorRequirements)(THIS_ ALLOCATOR_PROPERTIES*) PURE;
411  STDMETHOD(Receive)(THIS_ IMediaSample*) PURE;
412  STDMETHOD(ReceiveMultiple)(THIS_ IMediaSample**,LONG,LONG*) PURE;
413  STDMETHOD(ReceiveCanBlock)(THIS) PURE;
414};
415#undef INTERFACE
416
417#define INTERFACE ISampleGrabberCB
418DECLARE_INTERFACE_(ISampleGrabberCB,IUnknown)
419{
420  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
421  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
422  STDMETHOD_(ULONG,Release)(THIS) PURE;
423  STDMETHOD(SampleCB)(THIS_ double,IMediaSample*) PURE;
424  STDMETHOD(BufferCB)(THIS_ double,BYTE*,long) PURE;
425};
426#undef INTERFACE
427
428#define INTERFACE ISampleGrabber
429DECLARE_INTERFACE_(ISampleGrabber,IUnknown)
430{
431  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
432  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
433  STDMETHOD_(ULONG,Release)(THIS) PURE;
434  STDMETHOD(SetOneShot)(THIS_ BOOL) PURE;
435  STDMETHOD(SetMediaType)(THIS_ const AM_MEDIA_TYPE*) PURE;
436  STDMETHOD(GetConnectedMediaType)(THIS_ AM_MEDIA_TYPE*) PURE;
437  STDMETHOD(SetBufferSamples)(THIS_ BOOL) PURE;
438  STDMETHOD(GetCurrentBuffer)(THIS_ long*,long*) PURE;
439  STDMETHOD(GetCurrentSample)(THIS_ IMediaSample**) PURE;
440  STDMETHOD(SetCallBack)(THIS_ ISampleGrabberCB *,long) PURE;
441};
442#undef INTERFACE
443
444ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num )
445{
446        ComPtr< IPin > retVal;
447        ComPtr< IEnumPins > enumPins;
448        if (filter->EnumPins( &enumPins )!=S_OK){
449                ms_error("Error getting pin enumerator" );
450                return retVal;
451        }
452        ULONG found;
453        ComPtr< IPin > pin;
454        while ( enumPins->Next( 1, &pin, &found ) == S_OK ) {
455                PIN_DIRECTION pinDirection = (PIN_DIRECTION)( -1 );
456                pin->QueryDirection( &pinDirection );
457                if ( pinDirection == direction ) {
458                        if ( num == 0 ) {
459                                retVal = pin;
460                                break;
461                        };
462                        num--;
463                };
464        };
465        return retVal;
466}
467
468
469
470class DSCapture : public ISampleGrabberCB{
471public:
472        DSCapture(){
473                qinit(&_rq);
474                ms_mutex_init(&_mutex,NULL);
475                _vsize=MS_VIDEO_SIZE_CIF;
476                _fps=15;
477                _start_time=0;
478                _frame_count=0;
479                _pixfmt=MS_YUV420P;
480        }
481        virtual ~DSCapture(){
482                flushq(&_rq,0);
483                ms_mutex_destroy(&_mutex);
484        }
485        STDMETHODIMP QueryInterface( REFIID riid, void **ppv );
486        STDMETHODIMP_(ULONG) AddRef(void);
487        STDMETHODIMP_(ULONG) Release(void);
488        STDMETHODIMP SampleCB(double,IMediaSample*);
489        STDMETHODIMP BufferCB(double,BYTE*,long);
490        int startDshowGraph();
491        void stopAndClean();
492        mblk_t *readFrame(){
493                mblk_t *ret=NULL;
494                ms_mutex_lock(&_mutex);
495                ret=getq(&_rq);
496                ms_mutex_unlock(&_mutex);
497                return ret;
498        }
499        bool isTimeToSend(uint64_t ticker_time);
500        MSVideoSize getVSize()const{
501                return _vsize;
502        }
503        void setVSize(MSVideoSize vsize){
504                _vsize=vsize;
505        }
506        void setFps(float fps){
507                _fps=fps;
508        }
509        MSPixFmt getPixFmt()const{
510                return _pixfmt;
511        }
512        void setDeviceIndex(int index){
513                _devid=index;
514        }
515protected:
516        long m_refCount;
517private:
518        int     selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count);
519        int _devid;
520        MSVideoSize _vsize;
521        queue_t _rq;
522        ms_mutex_t _mutex;
523        float _fps;
524        float _start_time;
525        int _frame_count;
526        MSPixFmt _pixfmt;
527        ComPtr< IBaseFilter > _source;
528        ComPtr< IBaseFilter > _nullRenderer;
529        ComPtr< IBaseFilter > _grabberBase;
530        ComPtr< IMediaControl > _mediaControl;
531        ComPtr< IMediaEvent > _mediaEvent;
532};
533
534
535STDMETHODIMP DSCapture::QueryInterface(REFIID riid, void **ppv)
536{
537  HRESULT retval;
538  if ( ppv == NULL ) return E_POINTER;
539  /*
540  if ( riid == IID_IUnknown ) {
541    *ppv = static_cast< IUnknown * >( this );
542    AddRef();
543    retval = S_OK;
544  } else if ( riid == IID_ISampleGrabberCB ) {
545    *ppv = static_cast< ISampleGrabberCB * >( this );
546    AddRef();
547    retval = S_OK;
548    } else */ {
549#ifndef NDEBUG
550    cerr << setbase( 16 ) << setfill('0')
551         << "DEFINE_GUID( ..., 0x" << setw(8) << (int)riid.Data1 << ", 0x"
552         << setw(4) << (int)riid.Data2 << "," << endl
553         << "             0x"
554         << setw(4) << (int)riid.Data3 << ", 0x" << setw(2)
555         << (int)riid.Data4[0] << ", 0x"
556         << (int)riid.Data4[1] << ", 0x"
557         << (int)riid.Data4[2] << ", 0x"
558         << (int)riid.Data4[3] << ", 0x"
559         << (int)riid.Data4[4] << ", 0x"
560         << (int)riid.Data4[5] << ", 0x"
561         << (int)riid.Data4[6] << ", 0x"
562         << (int)riid.Data4[7] << " ) ?" << endl
563         << setfill( ' ' ) << setw( 0 ) << setbase( 10 );
564#endif
565    retval = E_NOINTERFACE;
566  };
567  return retval;
568};
569
570STDMETHODIMP_(ULONG) DSCapture::AddRef(){
571        m_refCount++;
572        return m_refCount;
573}
574
575STDMETHODIMP_(ULONG) DSCapture::Release()
576{
577  ms_message("DSCapture::Release");
578  if ( !InterlockedDecrement( &m_refCount ) ) {
579                int refcnt=m_refCount;
580                delete this;
581                return refcnt;
582        }
583  return m_refCount;
584}
585
586static void dummy(void*p){
587}
588
589STDMETHODIMP DSCapture::SampleCB( double par1 , IMediaSample * sample)
590{
591        uint8_t *p;
592        unsigned int size;
593        if (sample->GetPointer(&p)!=S_OK){
594                ms_error("error in GetPointer()");
595                return S_OK;
596        }
597        size=sample->GetSize();
598        //ms_message( "DSCapture::SampleCB pointer=%p, size=%i",p,size);
599        mblk_t *m=esballoc(p,size,0,dummy);
600        m->b_wptr+=size;
601        ms_mutex_lock(&_mutex);
602        putq(&_rq,m);
603        ms_mutex_unlock(&_mutex);
604        return S_OK;
605}
606
607
608
609STDMETHODIMP DSCapture::BufferCB( double, BYTE *b, long len)
610{
611        ms_message("DSCapture::BufferCB");
612        return S_OK;
613}
614
615static void dscap_init(MSFilter *f){
616        DSCapture *s=new DSCapture();
617        f->data=s;
618}
619
620
621
622static void dscap_uninit(MSFilter *f){
623        DSCapture *s=(DSCapture*)f->data;
624        s->Release();
625}
626
627static char * fourcc_to_char(char *str, uint32_t fcc){
628        memcpy(str,&fcc,4);
629        str[4]='\0';
630        return str;
631}
632
633static int find_best_format(ComPtr<IAMStreamConfig> streamConfig, int count, MSVideoSize *requested_size, MSPixFmt requested_fmt ){
634        int i;
635        MSVideoSize best_found=(MSVideoSize){32768,32768};
636        int best_index=-1;
637        char fccstr[5];
638        char selected_fcc[5];
639        for (i=0; i<count; i++ ) {
640                VIDEO_STREAM_CONFIG_CAPS videoConfig;
641                AM_MEDIA_TYPE *mediaType;
642                COERRORMACRO( streamConfig->GetStreamCaps( i, &mediaType,
643                                                 (BYTE *)&videoConfig ),
644                    Error, , "Error getting stream capabilities" );
645                if ( mediaType->majortype == MEDIATYPE_Video &&
646           mediaType->cbFormat != 0 ) {
647                        VIDEOINFOHEADER *infoHeader = (VIDEOINFOHEADER*)mediaType->pbFormat;
648                        ms_message("Seeing format %ix%i %s",infoHeader->bmiHeader.biWidth,infoHeader->bmiHeader.biHeight,
649                                        fourcc_to_char(fccstr,infoHeader->bmiHeader.biCompression));
650                        if (ms_fourcc_to_pix_fmt(infoHeader->bmiHeader.biCompression)==requested_fmt){
651                                MSVideoSize cur;
652                                cur.width=infoHeader->bmiHeader.biWidth;
653                                cur.height=infoHeader->bmiHeader.biHeight;
654                                if (ms_video_size_greater_than(cur,*requested_size)){
655                                        if (ms_video_size_greater_than(best_found,cur)){
656                                                best_found=cur;
657                                                best_index=i;
658                                                fourcc_to_char(selected_fcc,infoHeader->bmiHeader.biCompression);
659                                        }
660                                }
661                        }
662                };
663                if ( mediaType->cbFormat != 0 )
664                        CoTaskMemFree( (PVOID)mediaType->pbFormat );
665                if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release();
666                        CoTaskMemFree( (PVOID)mediaType );
667        }
668        if (best_index!=-1) {
669                *requested_size=best_found;
670                ms_message("Best camera format is %s %ix%i",selected_fcc,best_found.width,best_found.height);
671        }
672        return best_index;
673}
674
675int DSCapture::selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count){
676        int index;
677        _pixfmt=MS_YUV420P;
678        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
679        if (index!=-1) goto success;
680        _pixfmt=MS_YUY2;
681        index=find_best_format(streamConfig, count, &_vsize,_pixfmt);
682        if (index!=-1) goto success;
683        _pixfmt=MS_YUYV;
684        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
685        if (index!=-1) goto success;
686        _pixfmt=MS_RGB24;
687        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
688        if (index!=-1) {
689                _pixfmt=MS_RGB24_REV;
690                goto success;
691        }
692        ms_error("This camera does not support any of our pixel formats.");
693        return -1;
694       
695        success:
696        VIDEO_STREAM_CONFIG_CAPS videoConfig;
697        AM_MEDIA_TYPE *mediaType;
698        COERRORMACRO( streamConfig->GetStreamCaps( index, &mediaType,
699                                                 (BYTE *)&videoConfig ),
700                                Error, , "Error getting stream capabilities" );
701    streamConfig->SetFormat( mediaType );
702    return 0;
703}
704
705int DSCapture::startDshowGraph(){
706        ComPtr< ICreateDevEnum > createDevEnum;
707        CoInitialize(NULL);
708    createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
709                                    IID_ICreateDevEnum, "Could not create "
710                                    "device enumerator" );
711    ComPtr< IEnumMoniker > enumMoniker;
712    if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
713                ms_error("Fail to create class enumerator.");
714                return -1;
715        }
716    createDevEnum.reset();
717    enumMoniker->Reset();
718
719    int index = 0;
720    ULONG fetched = 0;
721        ComPtr< IGraphBuilder > graphBuilder;
722        graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder,
723                                   "Could not create graph builder "
724                                   "interface" );
725    ComPtr< IMoniker > moniker;
726    for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
727                if (i==_devid){
728                        if (moniker->BindToObject( 0, 0, IID_IBaseFilter, (void **)&_source )!=S_OK){
729                                ms_error("Error binding moniker to base filter" );
730                                return -1;
731                        }
732                }
733        }
734        if (_source.get()==0){
735                ms_error("Could not interface with webcam devid=%i",_devid);
736                return -1;
737        }
738        moniker.reset();
739    enumMoniker.reset();
740    if (graphBuilder->AddFilter( _source.get(), L"Source" )!=S_OK){
741        ms_error("Error adding camera source to filter graph" );
742        return -1;
743        }
744    ComPtr< IPin > sourceOut = getPin( _source.get(), PINDIR_OUTPUT, 0 );
745    if (sourceOut.get()==NULL){
746                ms_error("Error getting output pin of camera source" );
747                return -1;
748        }
749    ComPtr< IAMStreamConfig > streamConfig;
750    if (sourceOut->QueryInterface( IID_IAMStreamConfig,
751                                  (void **)&streamConfig )!=S_OK){
752        ms_error("Error requesting stream configuration API" );
753        return -1;
754        }
755    int count, size;
756    if (streamConfig->GetNumberOfCapabilities( &count, &size )!=S_OK){
757        ms_error("Error getting number of capabilities" );
758        return -1;
759        }
760    if (selectBestFormat(streamConfig,count)!=0){
761                return -1;
762        }
763    streamConfig.reset();
764
765    if (CoCreateInstance( CLSID_SampleGrabber, NULL,
766                                    CLSCTX_INPROC, IID_IBaseFilter,
767                                    (void **)&_grabberBase )!=S_OK){
768        ms_error("Error creating sample grabber" );
769        return -1;
770        }
771    if (graphBuilder->AddFilter( _grabberBase.get(), L"Grabber" )!=S_OK){
772                ms_error("Error adding sample grabber to filter graph");
773                return -1;
774        }
775    ComPtr< ISampleGrabber > sampleGrabber;
776    if (_grabberBase->QueryInterface( IID_ISampleGrabber,
777                                               (void **)&sampleGrabber )!=S_OK){
778                ms_error("Error requesting sample grabber interface");
779                return -1;
780        }
781    if (sampleGrabber->SetOneShot( FALSE )!=S_OK){
782        ms_error("Error disabling one-shot mode" );
783        return -1;
784        }
785    if (sampleGrabber->SetBufferSamples( TRUE )!=S_OK){
786        ms_error("Error enabling buffer sampling" );
787        return -1;
788        }
789        if (sampleGrabber->SetCallBack(this, 0 )!=S_OK){
790                ms_error("Error setting callback interface for grabbing" );
791                return -1;
792        }
793    ComPtr< IPin > grabberIn = getPin( _grabberBase.get(), PINDIR_INPUT, 0 );
794    if (grabberIn.get() == NULL){
795        ms_error("Error getting input of sample grabber");
796                return -1;
797        }
798    ComPtr< IPin > grabberOut = getPin( _grabberBase.get(), PINDIR_OUTPUT, 0 );
799        if (grabberOut.get()==NULL){
800                ms_error("Error getting output of sample grabber" );
801                return -1;
802        }
803    if (CoCreateInstance( CLSID_NullRenderer, NULL,
804                                    CLSCTX_INPROC, IID_IBaseFilter,
805                                    (void **)&_nullRenderer )!=S_OK){
806                ms_error("Error creating Null Renderer" );
807                return -1;
808        }
809        if (graphBuilder->AddFilter( _nullRenderer.get(), L"Sink" )!=S_OK){
810        ms_error("Error adding null renderer to filter graph" );
811        return -1;
812        }
813    ComPtr< IPin > nullIn = getPin( _nullRenderer.get(), PINDIR_INPUT, 0 );
814        if (graphBuilder->Connect( sourceOut.get(), grabberIn.get() )!=S_OK){
815        ms_error("Error connecting source to sample grabber" );
816        return -1;
817        }
818    if (graphBuilder->Connect( grabberOut.get(), nullIn.get() )!=S_OK){
819        ms_error("Error connecting sample grabber to sink" );
820        return -1;
821        }
822    ms_message("Directshow graph is now ready to run.");
823
824    if (graphBuilder->QueryInterface( IID_IMediaControl,
825                                                (void **)&_mediaControl )!=S_OK){
826        ms_error("Error requesting media control interface" );
827                return -1;
828        }
829    HRESULT r=_mediaControl->Run();
830        if (r!=S_OK && r!=S_FALSE){
831                ms_error("Error starting graph (%i)",r);
832        }
833    ms_message("Graph started");
834    if (graphBuilder->QueryInterface( IID_IMediaEvent,
835                                        (void **)&_mediaEvent )!=S_OK){
836        ms_error("Error requesting event interface" );
837        return -1;
838        }
839}
840
841void DSCapture::stopAndClean(){
842        if (_mediaControl.get()!=NULL){
843                _mediaControl->Stop();
844        long evCode = 0;
845        _mediaEvent->WaitForCompletion( INFINITE, &evCode );
846        }
847        _source.reset();
848        _grabberBase.reset();
849        _nullRenderer.reset();
850        _mediaControl.reset();
851        _mediaEvent.reset();
852        flushq(&_rq,0);
853}
854
855bool DSCapture::isTimeToSend(uint64_t ticker_time){
856        if (_frame_count==-1){
857                _start_time=(float)ticker_time;
858                _frame_count=0;
859        }
860        int cur_frame=(int)(((float)ticker_time-_start_time)*_fps/1000.0);
861        if (cur_frame>_frame_count){
862                _frame_count++;
863                return true;
864        }
865        return false;
866}
867
868static void dscap_preprocess(MSFilter * obj){
869        DSCapture *s=(DSCapture*)obj->data;
870        s->startDshowGraph();
871}
872
873static void dscap_postprocess(MSFilter * obj){
874        DSCapture *s=(DSCapture*)obj->data;
875        s->stopAndClean();
876}
877
878static void dscap_process(MSFilter * obj){
879        DSCapture *s=(DSCapture*)obj->data;
880        mblk_t *m;
881        uint32_t timestamp;
882        int cur_frame;
883
884        if (s->isTimeToSend(obj->ticker->time)){
885                mblk_t *om=NULL;
886                /*keep the most recent frame if several frames have been captured */
887                while((m=s->readFrame())!=NULL){
888                        if (om!=NULL) freemsg(om);
889                        om=m;
890                }
891                if (om!=NULL){
892                        timestamp=(uint32_t)(obj->ticker->time*90);/* rtp uses a 90000 Hz clockrate for video*/
893                        mblk_set_timestamp_info(om,timestamp);
894                        ms_queue_put(obj->outputs[0],om);
895                }
896        }
897}
898
899static int dscap_set_fps(MSFilter *f, void *arg){
900        DSCapture *s=(DSCapture*)f->data;
901        s->setFps(*(float*)arg);
902        return 0;
903}
904
905static int dscap_get_pix_fmt(MSFilter *f,void *arg){
906        DSCapture *s=(DSCapture*)f->data;
907        *((MSPixFmt*)arg)=s->getPixFmt();
908        return 0;
909}
910
911static int dscap_set_vsize(MSFilter *f, void *arg){
912        DSCapture *s=(DSCapture*)f->data;
913        s->setVSize(*((MSVideoSize*)arg));
914        return 0;
915}
916
917static int dscap_get_vsize(MSFilter *f, void *arg){
918        DSCapture *s=(DSCapture*)f->data;
919        MSVideoSize *vs=(MSVideoSize*)arg;
920        *vs=s->getVSize();
921        return 0;
922}
923
924static MSFilterMethod methods[]={
925        {       MS_FILTER_SET_FPS       ,       dscap_set_fps   },
926        {       MS_FILTER_GET_PIX_FMT   ,       dscap_get_pix_fmt       },
927        {       MS_FILTER_SET_VIDEO_SIZE, dscap_set_vsize       },
928        {       MS_FILTER_GET_VIDEO_SIZE, dscap_get_vsize       },
929        {       0                                                               ,       NULL                    }
930};
931
932MSFilterDesc ms_dscap_desc={
933        MS_FILTER_PLUGIN_ID,
934        "MSDsCap",
935        N_("A webcam grabber based on directshow."),
936        MS_FILTER_OTHER,
937        NULL,
938        0,
939        1,
940        dscap_init,
941        dscap_preprocess,
942        dscap_process,
943        dscap_postprocess,
944        dscap_uninit,
945        methods
946};
947
948
949static void ms_dshow_detect(MSWebCamManager *obj);
950static MSFilter * ms_dshow_create_reader(MSWebCam *obj){
951        MSFilter *f=ms_filter_new_from_desc(&ms_dscap_desc);
952        DSCapture *s=(DSCapture*)f->data;
953        s->setDeviceIndex((int)obj->data);
954        return f;
955}
956
957static MSWebCamDesc ms_dshow_cam_desc={
958        "Directshow capture",
959        &ms_dshow_detect,
960        NULL,
961        &ms_dshow_create_reader,
962        NULL
963};
964
965static void ms_dshow_detect(MSWebCamManager *obj){
966        int i;
967        MSWebCam *cam;
968        ComPtr<IPropertyBag> pBag;
969       
970        CoInitialize(NULL);
971 
972    ComPtr< ICreateDevEnum > createDevEnum;
973    createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
974                                    IID_ICreateDevEnum, "Could not create "
975                                    "device enumerator" );
976    ComPtr< IEnumMoniker > enumMoniker;
977    if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
978                ms_error("Fail to create class enumerator.");
979                return;
980        }
981    createDevEnum.reset();
982    enumMoniker->Reset();
983   
984    int index = 0;
985    ULONG fetched = 0;
986    ComPtr< IMoniker > moniker;
987    for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
988                VARIANT var;
989                if (moniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag )!=S_OK)
990                        continue;
991                VariantInit(&var);
992                if (pBag->Read( L"FriendlyName", &var, NULL )!=S_OK)
993                        continue;
994        char szName[256];
995                WideCharToMultiByte(CP_ACP,0,var.bstrVal,-1,szName,256,0,0);
996                MSWebCam *cam=ms_web_cam_new(&ms_dshow_cam_desc);
997        cam->name=ms_strdup(szName);
998        cam->data=(void*)i;
999                ms_web_cam_manager_prepend_cam(obj,cam);
1000        VariantClear(&var);
1001        }
1002    enumMoniker.reset();
1003}
1004
1005extern "C" void libmsdscap_init(void){
1006                ms_web_cam_manager_register_desc(ms_web_cam_manager_get(),&ms_dshow_cam_desc);
1007}
Note: See TracBrowser for help on using the repository browser.