~ubuntu-branches/ubuntu/vivid/linphone/vivid

« back to all changes in this revision

Viewing changes to mediastreamer2/src/msdscap-mingw.cc

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2009-10-14 08:26:02 UTC
  • mfrom: (1.3.1 upstream) (6.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20091014082602-751618nxdjooja3l
Tags: 3.2.1-1
New upstream release 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
 
 
5
   Copyright (C) 2009 Simon Morlat
 
6
 
 
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.
 
11
 
 
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.
 
16
 
 
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/>. 
 
19
*/
 
20
/* 
 
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.
 
26
*/
 
27
 
 
28
 
 
29
#include <windows.h>
 
30
#include <winnls.h>
 
31
#include <errors.h>
 
32
#include <initguid.h>
 
33
#include <ocidl.h>
 
34
 
 
35
 
 
36
#include <mediastreamer2/mswebcam.h>
 
37
#include <mediastreamer2/msfilter.h>
 
38
#include <mediastreamer2/msticker.h>
 
39
#include <mediastreamer2/msvideo.h>
 
40
 
 
41
template <typename _ComT>
 
42
class ComPtr{
 
43
        private:
 
44
                _ComT *mPtr;
 
45
        public:
 
46
                int coCreateInstance(REFCLSID clsid, REFIID iid){
 
47
                        HRESULT res;
 
48
                        res=::CoCreateInstance(clsid,NULL,CLSCTX_INPROC,iid,
 
49
                                (void**)&mPtr);
 
50
                        return (res==S_OK) ? 0 : -1;
 
51
                }
 
52
                ComPtr() : mPtr(0){
 
53
                }
 
54
                ~ComPtr(){
 
55
                        reset();
 
56
                }
 
57
                ComPtr(const ComPtr<_ComT>& other) : mPtr(other.mPtr){
 
58
                        if (mPtr) mPtr->AddRef();
 
59
                }
 
60
                ComPtr<_ComT> & operator=(const ComPtr<_ComT> &other){
 
61
                        if (other.mPtr)
 
62
                                other.mPtr->AddRef();
 
63
                        if (mPtr)
 
64
                                mPtr->Release();
 
65
                        mPtr=other.mPtr;
 
66
                        return *this;
 
67
                }
 
68
                bool operator==(const ComPtr<_ComT> &other){
 
69
                        return other.mPtr==mPtr;
 
70
                }
 
71
                bool operator!=(const ComPtr<_ComT> &other){
 
72
                        return other.mPtr!=mPtr;
 
73
                }
 
74
                _ComT *get(){
 
75
                        return mPtr;
 
76
                }
 
77
                _ComT **operator&(){
 
78
                        return &mPtr;
 
79
                }
 
80
                _ComT * operator->(){
 
81
                        return mPtr;
 
82
                }
 
83
                void reset(){
 
84
                        if (mPtr){
 
85
                                mPtr->Release();
 
86
                                mPtr=0;
 
87
                        }
 
88
                }
 
89
};
 
90
 
 
91
 
 
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 );
 
150
 
 
151
using namespace std;
 
152
 
 
153
typedef LONGLONG REFERENCE_TIME;
 
154
 
 
155
typedef struct tagVIDEOINFOHEADER {
 
156
  RECT rcSource;
 
157
  RECT rcTarget;
 
158
  DWORD dwBitRate;
 
159
  DWORD dwBitErrorRate;
 
160
  REFERENCE_TIME AvgTimePerFrame;
 
161
  BITMAPINFOHEADER bmiHeader;
 
162
} VIDEOINFOHEADER;
 
163
 
 
164
typedef struct _AMMediaType {
 
165
  GUID majortype;
 
166
  GUID subtype;
 
167
  BOOL bFixedSizeSamples;
 
168
  BOOL bTemporalCompression;
 
169
  ULONG lSampleSize;
 
170
  GUID formattype;
 
171
  IUnknown *pUnk;
 
172
  ULONG cbFormat;
 
173
  BYTE *pbFormat;
 
174
} AM_MEDIA_TYPE;
 
175
 
 
176
DECLARE_ENUMERATOR_(IEnumMediaTypes,AM_MEDIA_TYPE*);
 
177
 
 
178
typedef struct _VIDEO_STREAM_CONFIG_CAPS
 
179
{
 
180
  GUID guid;
 
181
  ULONG VideoStandard;
 
182
  SIZE InputSize;
 
183
  SIZE MinCroppingSize;
 
184
  SIZE MaxCroppingSize;
 
185
  int CropGranularityX;
 
186
  int CropGranularityY;
 
187
  int CropAlignX;
 
188
  int CropAlignY;
 
189
  SIZE MinOutputSize;
 
190
  SIZE MaxOutputSize;
 
191
  int OutputGranularityX;
 
192
  int OutputGranularityY;
 
193
  int StretchTapsX;
 
194
  int StretchTapsY;
 
195
  int ShrinkTapsX;
 
196
  int ShrinkTapsY;
 
197
  LONGLONG MinFrameInterval;
 
198
  LONGLONG MaxFrameInterval;
 
199
  LONG MinBitsPerSecond;
 
200
  LONG MaxBitsPerSecond;
 
201
} VIDEO_STREAM_CONFIG_CAPS;
 
202
 
 
203
typedef LONGLONG REFERENCE_TIME;
 
204
 
 
205
typedef interface IBaseFilter IBaseFilter;
 
206
typedef interface IReferenceClock IReferenceClock;
 
207
typedef interface IFilterGraph IFilterGraph;
 
208
 
 
209
typedef enum _FilterState {
 
210
  State_Stopped,
 
211
  State_Paused,
 
212
  State_Running
 
213
} FILTER_STATE;
 
214
 
 
215
#define MAX_FILTER_NAME 128
 
216
typedef struct _FilterInfo {
 
217
  WCHAR achName[MAX_FILTER_NAME]; 
 
218
  IFilterGraph *pGraph;
 
219
} FILTER_INFO;
 
220
 
 
221
typedef enum _PinDirection {
 
222
  PINDIR_INPUT,
 
223
  PINDIR_OUTPUT
 
224
} PIN_DIRECTION;
 
225
 
 
226
#define MAX_PIN_NAME 128
 
227
typedef struct _PinInfo {
 
228
  IBaseFilter *pFilter;
 
229
  PIN_DIRECTION dir;
 
230
  WCHAR achName[MAX_PIN_NAME];
 
231
} PIN_INFO;
 
232
 
 
233
#define INTERFACE IPin
 
234
DECLARE_INTERFACE_(IPin,IUnknown)
 
235
{
 
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;
 
246
};
 
247
#undef INTERFACE
 
248
 
 
249
DECLARE_ENUMERATOR_(IEnumPins,IPin*);
 
250
 
 
251
typedef struct _AllocatorProperties {
 
252
  long cBuffers;
 
253
  long cbBuffer;
 
254
  long cbAlign;
 
255
  long cbPrefix;
 
256
} ALLOCATOR_PROPERTIES;
 
257
 
 
258
typedef LONG_PTR OAEVENT;
 
259
 
 
260
#define INTERFACE IMediaEvent
 
261
DECLARE_INTERFACE_(IMediaEvent,IDispatch)
 
262
{
 
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;
 
272
};
 
273
#undef INTERFACE
 
274
 
 
275
typedef long OAFilterState;
 
276
 
 
277
#define INTERFACE IMediaControl
 
278
DECLARE_INTERFACE_(IMediaControl,IDispatch)
 
279
{
 
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;
 
292
};
 
293
#undef INTERFACE
 
294
 
 
295
#define INTERFACE IVideoProcAmp
 
296
DECLARE_INTERFACE_(IVideoProcAmp,IUnknown)
 
297
{
 
298
  STDMETHOD(QueryInterface)(THIS_ REFIID,PVOID*) PURE;
 
299
  STDMETHOD_(ULONG,AddRef)(THIS) PURE;
 
300
  STDMETHOD_(ULONG,Release)(THIS) PURE;
 
301
};
 
302
#undef INTERFACE
 
303
 
 
304
#define INTERFACE IAMStreamConfig
 
305
DECLARE_INTERFACE_(IAMStreamConfig,IUnknown)
 
306
{
 
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;
 
314
};
 
315
#undef INTERFACE
 
316
 
 
317
#define INTERFACE IMediaFilter
 
318
DECLARE_INTERFACE_(IMediaFilter,IPersist)
 
319
{
 
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;
 
329
};
 
330
#undef INTERFACE
 
331
 
 
332
#define INTERFACE IBaseFilter
 
333
DECLARE_INTERFACE_(IBaseFilter,IMediaFilter)
 
334
{
 
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;
 
343
};
 
344
#undef INTERFACE
 
345
 
 
346
DECLARE_ENUMERATOR_(IEnumFilters,IBaseFilter*);
 
347
 
 
348
// #define INTERFACE IEnumFilters
 
349
// DECLARE_INTERFACE_(IEnumFilters,IUnknown)
 
350
// {
 
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;
 
358
// };
 
359
// #undef INTERFACE
 
360
 
 
361
#define INTERFACE IFilterGraph
 
362
DECLARE_INTERFACE_(IFilterGraph,IUnknown)
 
363
{
 
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;
 
375
};
 
376
#undef INTERFACE
 
377
 
 
378
#define INTERFACE IGraphBuilder
 
379
DECLARE_INTERFACE_(IGraphBuilder,IFilterGraph)
 
380
{
 
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;
 
391
};
 
392
#undef INTERFACE
 
393
 
 
394
#define INTERFACE ICreateDevEnum
 
395
DECLARE_INTERFACE_(ICreateDevEnum,IUnknown)
 
396
{
 
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;
 
401
};
 
402
#undef INTERFACE
 
403
 
 
404
#define INTERFACE IMediaSample
 
405
DECLARE_INTERFACE_(IMediaSample,IUnknown)
 
406
{
 
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;
 
412
};
 
413
/*
 
414
#define INTERFACE IMediaSample
 
415
DECLARE_INTERFACE_(IMediaSample, IUnknown)
 
416
{
 
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;
 
433
};
 
434
*/
 
435
 
 
436
 
 
437
#undef INTERFACE
 
438
 
 
439
#define INTERFACE IMemAllocator
 
440
DECLARE_INTERFACE_(IMemAllocator,IUnknown)
 
441
{
 
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;
 
451
};
 
452
#undef INTERFACE
 
453
 
 
454
#define INTERFACE IMemInputPin
 
455
DECLARE_INTERFACE_(IMemInputPin,IUnknown)
 
456
{
 
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;
 
466
};
 
467
#undef INTERFACE
 
468
 
 
469
#define INTERFACE ISampleGrabberCB
 
470
DECLARE_INTERFACE_(ISampleGrabberCB,IUnknown)
 
471
{
 
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;
 
477
};
 
478
#undef INTERFACE
 
479
 
 
480
#define INTERFACE ISampleGrabber
 
481
DECLARE_INTERFACE_(ISampleGrabber,IUnknown)
 
482
{
 
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;
 
493
};
 
494
#undef INTERFACE
 
495
 
 
496
ComPtr< IPin > getPin( IBaseFilter *filter, PIN_DIRECTION direction, int num )
 
497
{
 
498
        ComPtr< IPin > retVal;
 
499
        ComPtr< IEnumPins > enumPins;
 
500
        if (filter->EnumPins( &enumPins )!=S_OK){
 
501
                ms_error("Error getting pin enumerator" );
 
502
                return retVal;
 
503
        }
 
504
        ULONG found;
 
505
        ComPtr< IPin > pin;
 
506
        while ( enumPins->Next( 1, &pin, &found ) == S_OK ) {
 
507
                PIN_DIRECTION pinDirection = (PIN_DIRECTION)( -1 );
 
508
                pin->QueryDirection( &pinDirection );
 
509
                if ( pinDirection == direction ) {
 
510
                        if ( num == 0 ) {
 
511
                                retVal = pin;
 
512
                                break;
 
513
                        };
 
514
                        num--;
 
515
                };
 
516
        };
 
517
        return retVal;
 
518
}
 
519
 
 
520
 
 
521
 
 
522
class DSCapture : public ISampleGrabberCB{
 
523
public:
 
524
        DSCapture(){
 
525
                qinit(&_rq);
 
526
                ms_mutex_init(&_mutex,NULL);
 
527
                _vsize=MS_VIDEO_SIZE_CIF;
 
528
                _fps=15;
 
529
                _start_time=0;
 
530
                _frame_count=0;
 
531
                _pixfmt=MS_YUV420P;
 
532
                _ready=false;
 
533
                m_refCount=1;
 
534
        }
 
535
        virtual ~DSCapture(){
 
536
                if (_ready) stopAndClean();
 
537
                flushq(&_rq,0);
 
538
                ms_mutex_destroy(&_mutex);
 
539
        }
 
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();
 
546
        void stopAndClean();
 
547
        mblk_t *readFrame(){
 
548
                mblk_t *ret=NULL;
 
549
                ms_mutex_lock(&_mutex);
 
550
                ret=getq(&_rq);
 
551
                ms_mutex_unlock(&_mutex);
 
552
                return ret;
 
553
        }
 
554
        bool isTimeToSend(uint64_t ticker_time);
 
555
        MSVideoSize getVSize()const{
 
556
                return _vsize;
 
557
        }
 
558
        void setVSize(MSVideoSize vsize){
 
559
                _vsize=vsize;
 
560
        }
 
561
        void setFps(float fps){
 
562
                _fps=fps;
 
563
        }
 
564
        MSPixFmt getPixFmt(){
 
565
                if (!_ready) createDshowGraph(); /* so that _pixfmt is updated*/
 
566
                return _pixfmt;
 
567
        }
 
568
        void setDeviceIndex(int index){
 
569
                _devid=index;
 
570
        }
 
571
protected:
 
572
        long m_refCount;
 
573
private:
 
574
        int createDshowGraph();
 
575
        int     selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count);
 
576
        int _devid;
 
577
        MSVideoSize _vsize;
 
578
        queue_t _rq;
 
579
        ms_mutex_t _mutex;
 
580
        float _fps;
 
581
        float _start_time;
 
582
        int _frame_count;
 
583
        MSPixFmt _pixfmt;
 
584
        ComPtr< IGraphBuilder > _graphBuilder;
 
585
        ComPtr< IBaseFilter > _source;
 
586
        ComPtr< IBaseFilter > _nullRenderer;
 
587
        ComPtr< IBaseFilter > _grabberBase;
 
588
        ComPtr< IMediaControl > _mediaControl;
 
589
        ComPtr< IMediaEvent > _mediaEvent;
 
590
        bool _ready;
 
591
};
 
592
 
 
593
 
 
594
STDMETHODIMP DSCapture::QueryInterface(REFIID riid, void **ppv)
 
595
{
 
596
  HRESULT retval;
 
597
  if ( ppv == NULL ) return E_POINTER;
 
598
  /*
 
599
  if ( riid == IID_IUnknown ) {
 
600
    *ppv = static_cast< IUnknown * >( this );
 
601
    AddRef();
 
602
    retval = S_OK;
 
603
  } else if ( riid == IID_ISampleGrabberCB ) {
 
604
    *ppv = static_cast< ISampleGrabberCB * >( this );
 
605
    AddRef();
 
606
    retval = S_OK;
 
607
    } else */ {
 
608
    retval = E_NOINTERFACE;
 
609
  };
 
610
  return retval;
 
611
};
 
612
 
 
613
STDMETHODIMP_(ULONG) DSCapture::AddRef(){
 
614
        m_refCount++;
 
615
        return m_refCount;
 
616
}
 
617
 
 
618
STDMETHODIMP_(ULONG) DSCapture::Release()
 
619
{
 
620
  ms_message("DSCapture::Release");
 
621
  if ( !InterlockedDecrement( &m_refCount ) ) {
 
622
                int refcnt=m_refCount;
 
623
                delete this;
 
624
                return refcnt;
 
625
        }
 
626
  return m_refCount;
 
627
}
 
628
 
 
629
static void dummy(void*p){
 
630
}
 
631
 
 
632
STDMETHODIMP DSCapture::SampleCB( double par1 , IMediaSample * sample)
 
633
{
 
634
        uint8_t *p;
 
635
        unsigned int size;
 
636
        if (sample->GetPointer(&p)!=S_OK){
 
637
                ms_error("error in GetPointer()");
 
638
                return S_OK;
 
639
        }
 
640
        size=sample->GetSize();
 
641
        //ms_message( "DSCapture::SampleCB pointer=%p, size=%i",p,size);
 
642
        mblk_t *m=esballoc(p,size,0,dummy);
 
643
        m->b_wptr+=size;
 
644
        ms_mutex_lock(&_mutex);
 
645
        putq(&_rq,m);
 
646
        ms_mutex_unlock(&_mutex);
 
647
        return S_OK;
 
648
}
 
649
 
 
650
 
 
651
 
 
652
STDMETHODIMP DSCapture::BufferCB( double, BYTE *b, long len)
 
653
{
 
654
        ms_message("DSCapture::BufferCB");
 
655
        return S_OK;
 
656
}
 
657
 
 
658
static void dscap_init(MSFilter *f){
 
659
        DSCapture *s=new DSCapture();
 
660
        f->data=s;
 
661
}
 
662
 
 
663
 
 
664
 
 
665
static void dscap_uninit(MSFilter *f){
 
666
        DSCapture *s=(DSCapture*)f->data;
 
667
        s->Release();
 
668
}
 
669
 
 
670
static char * fourcc_to_char(char *str, uint32_t fcc){
 
671
        memcpy(str,&fcc,4);
 
672
        str[4]='\0';
 
673
        return str;
 
674
}
 
675
 
 
676
static int find_best_format(ComPtr<IAMStreamConfig> streamConfig, int count, MSVideoSize *requested_size, MSPixFmt requested_fmt ){
 
677
        int i;
 
678
        MSVideoSize best_found=(MSVideoSize){32768,32768};
 
679
        int best_index=-1;
 
680
        char fccstr[5];
 
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");
 
688
                        return -1;
 
689
                }
 
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){
 
696
                                MSVideoSize cur;
 
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)){
 
701
                                                best_found=cur;
 
702
                                                best_index=i;
 
703
                                                fourcc_to_char(selected_fcc,infoHeader->bmiHeader.biCompression);
 
704
                                        }
 
705
                                }
 
706
                        }
 
707
                };
 
708
                if ( mediaType->cbFormat != 0 )
 
709
                        CoTaskMemFree( (PVOID)mediaType->pbFormat );
 
710
                if ( mediaType->pUnk != NULL ) mediaType->pUnk->Release();
 
711
                        CoTaskMemFree( (PVOID)mediaType );
 
712
        }
 
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);
 
716
        }
 
717
        return best_index;
 
718
}
 
719
 
 
720
int DSCapture::selectBestFormat(ComPtr<IAMStreamConfig> streamConfig, int count){
 
721
        int index;
 
722
        _pixfmt=MS_YUV420P;
 
723
        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
 
724
        if (index!=-1) goto success;
 
725
        _pixfmt=MS_YUY2;
 
726
        index=find_best_format(streamConfig, count, &_vsize,_pixfmt);
 
727
        if (index!=-1) goto success;
 
728
        _pixfmt=MS_YUYV;
 
729
        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
 
730
        if (index!=-1) goto success;
 
731
        _pixfmt=MS_RGB24;
 
732
        index=find_best_format(streamConfig, count, &_vsize, _pixfmt);
 
733
        if (index!=-1) {
 
734
                _pixfmt=MS_RGB24_REV;
 
735
                goto success;
 
736
        }
 
737
        ms_error("This camera does not support any of our pixel formats.");
 
738
        return -1;
 
739
        
 
740
        success:
 
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" );
 
746
        }
 
747
        streamConfig->SetFormat( mediaType );
 
748
        return 0;
 
749
}
 
750
 
 
751
int DSCapture::createDshowGraph(){
 
752
        ComPtr< ICreateDevEnum > createDevEnum;
 
753
        
 
754
        CoInitialize(NULL);
 
755
        if (createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
 
756
                                    IID_ICreateDevEnum )==-1){
 
757
                ms_error("Could not create device enumerator");
 
758
                return -1;
 
759
        }
 
760
        ComPtr< IEnumMoniker > enumMoniker;
 
761
        if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
 
762
                ms_error("Fail to create class enumerator.");
 
763
                return -1;
 
764
        }
 
765
        createDevEnum.reset();
 
766
        enumMoniker->Reset();
 
767
 
 
768
        ULONG fetched = 0;
 
769
        if (_graphBuilder.coCreateInstance( CLSID_FilterGraph, IID_IGraphBuilder )!=0){
 
770
                ms_error("Could not create graph builder.");
 
771
                return -1;
 
772
        }
 
773
        ComPtr< IMoniker > moniker;
 
774
        for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
 
775
                if (i==_devid){
 
776
                        if (moniker->BindToObject( 0, 0, IID_IBaseFilter, (void **)&_source )!=S_OK){
 
777
                                ms_error("Error binding moniker to base filter" );
 
778
                                return -1;
 
779
                        }
 
780
                }
 
781
        }
 
782
        if (_source.get()==0){
 
783
                ms_error("Could not interface with webcam devid=%i",_devid);
 
784
                return -1;
 
785
        }
 
786
        moniker.reset();
 
787
        enumMoniker.reset();
 
788
        if (_graphBuilder->AddFilter( _source.get(), L"Source" )!=S_OK){
 
789
                ms_error("Error adding camera source to filter graph" );
 
790
                return -1;
 
791
        }
 
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" );
 
795
                return -1;
 
796
        }
 
797
        ComPtr< IAMStreamConfig > streamConfig;
 
798
        if (sourceOut->QueryInterface( IID_IAMStreamConfig,
 
799
                                  (void **)&streamConfig )!=S_OK){
 
800
                ms_error("Error requesting stream configuration API" );
 
801
                return -1;
 
802
        }
 
803
        int count, size;
 
804
        if (streamConfig->GetNumberOfCapabilities( &count, &size )!=S_OK){
 
805
                ms_error("Error getting number of capabilities" );
 
806
                return -1;
 
807
        }
 
808
        if (selectBestFormat(streamConfig,count)!=0){
 
809
                return -1;
 
810
        }
 
811
        streamConfig.reset();
 
812
 
 
813
        if (CoCreateInstance( CLSID_SampleGrabber, NULL,
 
814
                                    CLSCTX_INPROC, IID_IBaseFilter,
 
815
                                    (void **)&_grabberBase )!=S_OK){
 
816
                ms_error("Error creating sample grabber" );
 
817
                return -1;
 
818
        }
 
819
        if (_graphBuilder->AddFilter( _grabberBase.get(), L"Grabber" )!=S_OK){
 
820
                ms_error("Error adding sample grabber to filter graph");
 
821
                return -1;
 
822
        }
 
823
        ComPtr< ISampleGrabber > sampleGrabber;
 
824
        if (_grabberBase->QueryInterface( IID_ISampleGrabber,
 
825
                                               (void **)&sampleGrabber )!=S_OK){
 
826
                ms_error("Error requesting sample grabber interface");
 
827
                return -1;
 
828
        }
 
829
        if (sampleGrabber->SetOneShot( FALSE )!=S_OK){
 
830
                ms_error("Error disabling one-shot mode" );
 
831
                return -1;
 
832
        }
 
833
        if (sampleGrabber->SetBufferSamples( TRUE )!=S_OK){
 
834
                ms_error("Error enabling buffer sampling" );
 
835
                return -1;
 
836
        }
 
837
        if (sampleGrabber->SetCallBack(this, 0 )!=S_OK){
 
838
                ms_error("Error setting callback interface for grabbing" );
 
839
                return -1;
 
840
        }
 
841
    ComPtr< IPin > grabberIn = getPin( _grabberBase.get(), PINDIR_INPUT, 0 );
 
842
    if (grabberIn.get() == NULL){
 
843
        ms_error("Error getting input of sample grabber");
 
844
                return -1;
 
845
        }
 
846
    ComPtr< IPin > grabberOut = getPin( _grabberBase.get(), PINDIR_OUTPUT, 0 );
 
847
        if (grabberOut.get()==NULL){
 
848
                ms_error("Error getting output of sample grabber" );
 
849
                return -1;
 
850
        }
 
851
    if (CoCreateInstance( CLSID_NullRenderer, NULL,
 
852
                                    CLSCTX_INPROC, IID_IBaseFilter,
 
853
                                    (void **)&_nullRenderer )!=S_OK){
 
854
                ms_error("Error creating Null Renderer" );
 
855
                return -1;
 
856
        }
 
857
        if (_graphBuilder->AddFilter( _nullRenderer.get(), L"Sink" )!=S_OK){
 
858
        ms_error("Error adding null renderer to filter graph" );
 
859
        return -1;
 
860
        }
 
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" );
 
864
        return -1;
 
865
        }
 
866
    if (_graphBuilder->Connect( grabberOut.get(), nullIn.get() )!=S_OK){
 
867
        ms_error("Error connecting sample grabber to sink" );
 
868
        return -1;
 
869
        }
 
870
    ms_message("Directshow graph is now ready to run.");
 
871
 
 
872
    if (_graphBuilder->QueryInterface( IID_IMediaControl,
 
873
                                                (void **)&_mediaControl )!=S_OK){
 
874
        ms_error("Error requesting media control interface" );
 
875
                return -1;
 
876
        }
 
877
    if (_graphBuilder->QueryInterface( IID_IMediaEvent,
 
878
                                        (void **)&_mediaEvent )!=S_OK){
 
879
        ms_error("Error requesting event interface" );
 
880
        return -1;
 
881
        }
 
882
        _ready=true;
 
883
        return 0;
 
884
}
 
885
 
 
886
int DSCapture::startDshowGraph(){
 
887
        if (!_ready) {
 
888
                if (createDshowGraph()!=0) return -1;
 
889
        }
 
890
        HRESULT r=_mediaControl->Run();
 
891
        if (r!=S_OK && r!=S_FALSE){
 
892
                ms_error("Error starting graph (%i)",r);
 
893
                return -1;
 
894
        }
 
895
        ms_message("Graph started");
 
896
        return 0;
 
897
}
 
898
 
 
899
void DSCapture::stopAndClean(){
 
900
        if (_mediaControl.get()!=NULL){
 
901
                HRESULT r;
 
902
                r=_mediaControl->Stop();
 
903
                if (r!=S_OK){
 
904
                        ms_error("msdscap: Could not stop graph !");
 
905
                        fflush(NULL);
 
906
                }
 
907
        _graphBuilder->RemoveFilter(_source.get());
 
908
        _graphBuilder->RemoveFilter(_grabberBase.get());
 
909
                _graphBuilder->RemoveFilter(_nullRenderer.get());
 
910
        }
 
911
        _source.reset();
 
912
        _grabberBase.reset();
 
913
        _nullRenderer.reset();
 
914
        _mediaControl.reset();
 
915
        _mediaEvent.reset();
 
916
        _graphBuilder.reset();
 
917
        CoUninitialize();
 
918
        ms_mutex_lock(&_mutex);
 
919
        flushq(&_rq,0);
 
920
        ms_mutex_unlock(&_mutex);
 
921
        _ready=false;
 
922
}
 
923
 
 
924
bool DSCapture::isTimeToSend(uint64_t ticker_time){
 
925
        if (_frame_count==-1){
 
926
                _start_time=(float)ticker_time;
 
927
                _frame_count=0;
 
928
        }
 
929
        int cur_frame=(int)(((float)ticker_time-_start_time)*_fps/1000.0);
 
930
        if (cur_frame>_frame_count){
 
931
                _frame_count++;
 
932
                return true;
 
933
        }
 
934
        return false;
 
935
}
 
936
 
 
937
static void dscap_preprocess(MSFilter * obj){
 
938
        DSCapture *s=(DSCapture*)obj->data;
 
939
        s->startDshowGraph();
 
940
}
 
941
 
 
942
static void dscap_postprocess(MSFilter * obj){
 
943
        DSCapture *s=(DSCapture*)obj->data;
 
944
        s->stopAndClean();
 
945
}
 
946
 
 
947
static void dscap_process(MSFilter * obj){
 
948
        DSCapture *s=(DSCapture*)obj->data;
 
949
        mblk_t *m;
 
950
        uint32_t timestamp;
 
951
 
 
952
        if (s->isTimeToSend(obj->ticker->time)){
 
953
                mblk_t *om=NULL;
 
954
                /*keep the most recent frame if several frames have been captured */
 
955
                while((m=s->readFrame())!=NULL){
 
956
                        if (om!=NULL) freemsg(om);
 
957
                        om=m;
 
958
                }
 
959
                if (om!=NULL){
 
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);
 
963
                }
 
964
        }
 
965
}
 
966
 
 
967
static int dscap_set_fps(MSFilter *f, void *arg){
 
968
        DSCapture *s=(DSCapture*)f->data;
 
969
        s->setFps(*(float*)arg);
 
970
        return 0;
 
971
}
 
972
 
 
973
static int dscap_get_pix_fmt(MSFilter *f,void *arg){
 
974
        DSCapture *s=(DSCapture*)f->data;
 
975
        *((MSPixFmt*)arg)=s->getPixFmt();
 
976
        return 0;
 
977
}
 
978
 
 
979
static int dscap_set_vsize(MSFilter *f, void *arg){
 
980
        DSCapture *s=(DSCapture*)f->data;
 
981
        s->setVSize(*((MSVideoSize*)arg));
 
982
        return 0;
 
983
}
 
984
 
 
985
static int dscap_get_vsize(MSFilter *f, void *arg){
 
986
        DSCapture *s=(DSCapture*)f->data;
 
987
        MSVideoSize *vs=(MSVideoSize*)arg;
 
988
        *vs=s->getVSize();
 
989
        return 0;
 
990
}
 
991
 
 
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       },
 
997
        {       0                                                               ,       NULL                    }
 
998
};
 
999
 
 
1000
MSFilterDesc ms_dscap_desc={
 
1001
        MS_DSCAP_ID,
 
1002
        "MSDsCap",
 
1003
        N_("A webcam grabber based on directshow."),
 
1004
        MS_FILTER_OTHER,
 
1005
        NULL,
 
1006
        0,
 
1007
        1,
 
1008
        dscap_init,
 
1009
        dscap_preprocess,
 
1010
        dscap_process,
 
1011
        dscap_postprocess,
 
1012
        dscap_uninit,
 
1013
        methods
 
1014
};
 
1015
 
 
1016
 
 
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);
 
1022
        return f;
 
1023
}
 
1024
 
 
1025
MSWebCamDesc ms_dshow_cam_desc={
 
1026
        "Directshow capture",
 
1027
        &ms_dshow_detect,
 
1028
        NULL,
 
1029
        &ms_dshow_create_reader,
 
1030
        NULL
 
1031
};
 
1032
 
 
1033
static void ms_dshow_detect(MSWebCamManager *obj){
 
1034
        ComPtr<IPropertyBag> pBag;
 
1035
        
 
1036
        CoInitialize(NULL);
 
1037
 
 
1038
        ComPtr< ICreateDevEnum > createDevEnum;
 
1039
        if (createDevEnum.coCreateInstance( CLSID_SystemDeviceEnum,
 
1040
                                    IID_ICreateDevEnum)!=0){
 
1041
                ms_error( "Could not create device enumerator" );
 
1042
                return ;
 
1043
        }
 
1044
        ComPtr< IEnumMoniker > enumMoniker;
 
1045
        if (createDevEnum->CreateClassEnumerator( CLSID_VideoInputDeviceCategory, &enumMoniker, 0 )!=S_OK){
 
1046
                ms_error("Fail to create class enumerator.");
 
1047
                return;
 
1048
        }
 
1049
        createDevEnum.reset();
 
1050
        enumMoniker->Reset();
 
1051
    
 
1052
        ULONG fetched = 0;
 
1053
        ComPtr< IMoniker > moniker;
 
1054
        for ( int i=0;enumMoniker->Next( 1, &moniker, &fetched )==S_OK;++i ) {
 
1055
                VARIANT var;
 
1056
                if (moniker->BindToStorage( 0, 0, IID_IPropertyBag, (void**) &pBag )!=S_OK)
 
1057
                        continue;
 
1058
                VariantInit(&var);
 
1059
                if (pBag->Read( L"FriendlyName", &var, NULL )!=S_OK)
 
1060
                        continue;
 
1061
                char szName[256];
 
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);
 
1065
                cam->data=(void*)i;
 
1066
                ms_web_cam_manager_prepend_cam(obj,cam);
 
1067
                VariantClear(&var);
 
1068
        }
 
1069
        enumMoniker.reset();
 
1070
}
 
1071