CLAHE Python bindings
[profile/ivi/opencv.git] / modules / highgui / src / cap_dshow.cpp
1 /*M///////////////////////////////////////////////////////////////////////////////////////
2 //
3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4 //
5 //  By downloading, copying, installing or using the software you agree to this license.
6 //  If you do not agree to this license, do not download, install,
7 //  copy or use the software.
8 //
9 //
10 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "precomp.hpp"
43
44 #if (defined WIN32 || defined _WIN32) && defined HAVE_DSHOW
45
46 /*
47    DirectShow-based Video Capturing module is based on
48    videoInput library by Theodore Watson:
49    http://muonics.net/school/spring05/videoInput/
50
51    Below is the original copyright
52 */
53
54 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
60 //THE SOFTWARE.
61
62 //////////////////////////////////////////////////////////
63 //Written by Theodore Watson - theo.watson@gmail.com    //
64 //Do whatever you want with this code but if you find   //
65 //a bug or make an improvement I would love to know!    //
66 //                                                      //
67 //Warning This code is experimental                     //
68 //use at your own risk :)                               //
69 //////////////////////////////////////////////////////////
70 /////////////////////////////////////////////////////////
71 /*                     Shoutouts
72
73 Thanks to:
74
75            Dillip Kumar Kara for crossbar code.
76            Zachary Lieberman for getting me into this stuff
77            and for being so generous with time and code.
78            The guys at Potion Design for helping me with VC++
79            Josh Fisher for being a serious C++ nerd :)
80            Golan Levin for helping me debug the strangest
81            and slowest bug in the world!
82
83            And all the people using this library who send in
84            bugs, suggestions and improvements who keep me working on
85            the next version - yeah thanks a lot ;)
86
87 */
88 /////////////////////////////////////////////////////////
89
90 #include "precomp.hpp"
91
92 #if defined _MSC_VER && _MSC_VER >= 100
93 //'sprintf': name was marked as #pragma deprecated
94 #pragma warning(disable: 4995)
95 #endif
96
97 #include <tchar.h>
98 #include <stdlib.h>
99 #include <stdio.h>
100 #include <math.h>
101 #include <string.h>
102 #include <wchar.h>
103
104 #include <vector>
105
106 //Include Directshow stuff here so we don't worry about needing all the h files.
107 #if defined _MSC_VER && _MSC_VER >= 1500
108 #  include "DShow.h"
109 #  include "strmif.h"
110 #  include "Aviriff.h"
111 #  include "dvdmedia.h"
112 #  include "bdaiface.h"
113 #else
114 #  ifdef _MSC_VER
115 #  define __extension__
116    typedef BOOL WINBOOL;
117 #endif
118
119 #include "dshow/dshow.h"
120 #include "dshow/dvdmedia.h"
121 #include "dshow/bdatypes.h"
122
123 interface IEnumPIDMap : public IUnknown
124 {
125 public:
126     virtual HRESULT STDMETHODCALLTYPE Next(
127         /* [in] */ ULONG cRequest,
128         /* [size_is][out][in] */ PID_MAP *pPIDMap,
129         /* [out] */ ULONG *pcReceived) = 0;
130
131     virtual HRESULT STDMETHODCALLTYPE Skip(
132         /* [in] */ ULONG cRecords) = 0;
133
134     virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
135
136     virtual HRESULT STDMETHODCALLTYPE Clone(
137         /* [out] */ IEnumPIDMap **ppIEnumPIDMap) = 0;
138
139     virtual ~IEnumPIDMap() {}
140 };
141
142 interface IMPEG2PIDMap : public IUnknown
143 {
144     virtual HRESULT STDMETHODCALLTYPE MapPID(
145         /* [in] */ ULONG culPID,
146         /* [in] */ ULONG *pulPID,
147         /* [in] */ MEDIA_SAMPLE_CONTENT MediaSampleContent) = 0;
148
149     virtual HRESULT STDMETHODCALLTYPE UnmapPID(
150         /* [in] */ ULONG culPID,
151         /* [in] */ ULONG *pulPID) = 0;
152
153     virtual HRESULT STDMETHODCALLTYPE EnumPIDMap(
154         /* [out] */ IEnumPIDMap **pIEnumPIDMap) = 0;
155
156     virtual ~IMPEG2PIDMap() {}
157 };
158
159 #endif
160
161 //for threading
162 #include <process.h>
163
164 //this is for TryEnterCriticalSection
165 #ifndef _WIN32_WINNT
166 #define _WIN32_WINNT 0x400
167 #endif
168
169
170 /*
171 MEDIASUBTYPE_I420 : TGUID ='{30323449-0000-0010-8000-00AA00389B71}';
172 MEDIASUBTYPE_Y800 : TGUID ='{30303859-0000-0010-8000-00AA00389B71}';
173 MEDIASUBTYPE_Y8   : TGUID ='{20203859-0000-0010-8000-00AA00389B71}';
174 MEDIASUBTYPE_Y160 : TGUID ='{30363159-0000-0010-8000-00AA00389B71}';
175 MEDIASUBTYPE_YV16 : TGUID ='{32315659-0000-0010-8000-00AA00389B71}';
176 MEDIASUBTYPE_Y422 : TGUID ='{32323459-0000-0010-8000-00AA00389B71}';
177 MEDIASUBTYPE_GREY : TGUID ='{59455247-0000-0010-8000-00AA00389B71}';
178 */
179
180 #include <initguid.h>
181
182 DEFINE_GUID(MEDIASUBTYPE_GREY, 0x59455247, 0x0000, 0x0010, 0x80, 0x00,
183     0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
184 DEFINE_GUID(MEDIASUBTYPE_Y8, 0x20203859, 0x0000, 0x0010, 0x80, 0x00,
185     0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
186 DEFINE_GUID(MEDIASUBTYPE_Y800, 0x30303859, 0x0000, 0x0010, 0x80, 0x00,
187     0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
188
189 DEFINE_GUID(CLSID_CaptureGraphBuilder2,0xbf87b6e1,0x8c27,0x11d0,0xb3,0xf0,0x00,0xaa,0x00,0x37,0x61,0xc5);
190 DEFINE_GUID(CLSID_FilterGraph,0xe436ebb3,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
191 DEFINE_GUID(CLSID_NullRenderer,0xc1f400a4,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37);
192 DEFINE_GUID(CLSID_SampleGrabber,0xc1f400a0,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37);
193 DEFINE_GUID(CLSID_SystemDeviceEnum,0x62be5d10,0x60eb,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
194 DEFINE_GUID(CLSID_VideoInputDeviceCategory,0x860bb310,0x5d01,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
195 DEFINE_GUID(FORMAT_VideoInfo,0x05589f80,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a);
196 DEFINE_GUID(IID_IAMAnalogVideoDecoder,0xc6e13350,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
197 DEFINE_GUID(IID_IAMCameraControl,0xc6e13370,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
198 DEFINE_GUID(IID_IAMCrossbar,0xc6e13380,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
199 DEFINE_GUID(IID_IAMStreamConfig,0xc6e13340,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
200 DEFINE_GUID(IID_IAMVideoProcAmp,0xc6e13360,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
201 DEFINE_GUID(IID_IBaseFilter,0x56a86895,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
202 DEFINE_GUID(IID_ICaptureGraphBuilder2,0x93e5a4e0,0x2d50,0x11d2,0xab,0xfa,0x00,0xa0,0xc9,0xc6,0xe3,0x8d);
203 DEFINE_GUID(IID_ICreateDevEnum,0x29840822,0x5b84,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
204 DEFINE_GUID(IID_IGraphBuilder,0x56a868a9,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
205 DEFINE_GUID(IID_IMPEG2PIDMap,0xafb6c2a1,0x2c41,0x11d3,0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a);
206 DEFINE_GUID(IID_IMediaControl,0x56a868b1,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
207 DEFINE_GUID(IID_IMediaFilter,0x56a86899,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
208 DEFINE_GUID(IID_ISampleGrabber,0x6b652fff,0x11fe,0x4fce,0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f);
209 DEFINE_GUID(LOOK_UPSTREAM_ONLY,0xac798be0,0x98e3,0x11d1,0xb3,0xf1,0x00,0xaa,0x00,0x37,0x61,0xc5);
210 DEFINE_GUID(MEDIASUBTYPE_AYUV,0x56555941,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
211 DEFINE_GUID(MEDIASUBTYPE_IYUV,0x56555949,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
212 DEFINE_GUID(MEDIASUBTYPE_RGB24,0xe436eb7d,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
213 DEFINE_GUID(MEDIASUBTYPE_RGB32,0xe436eb7e,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
214 DEFINE_GUID(MEDIASUBTYPE_RGB555,0xe436eb7c,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
215 DEFINE_GUID(MEDIASUBTYPE_RGB565,0xe436eb7b,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
216 DEFINE_GUID(MEDIASUBTYPE_I420,0x49343230,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
217 DEFINE_GUID(MEDIASUBTYPE_UYVY,0x59565955,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
218 DEFINE_GUID(MEDIASUBTYPE_Y211,0x31313259,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
219 DEFINE_GUID(MEDIASUBTYPE_Y411,0x31313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
220 DEFINE_GUID(MEDIASUBTYPE_Y41P,0x50313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
221 DEFINE_GUID(MEDIASUBTYPE_YUY2,0x32595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
222 DEFINE_GUID(MEDIASUBTYPE_YUYV,0x56595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
223 DEFINE_GUID(MEDIASUBTYPE_YV12,0x32315659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
224 DEFINE_GUID(MEDIASUBTYPE_YVU9,0x39555659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
225 DEFINE_GUID(MEDIASUBTYPE_YVYU,0x55595659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
226 DEFINE_GUID(MEDIASUBTYPE_MJPG,0x47504A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); // MGB
227 DEFINE_GUID(MEDIATYPE_Interleaved,0x73766169,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
228 DEFINE_GUID(MEDIATYPE_Video,0x73646976,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
229 DEFINE_GUID(PIN_CATEGORY_CAPTURE,0xfb6c4281,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba);
230 DEFINE_GUID(PIN_CATEGORY_PREVIEW,0xfb6c4282,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba);
231
232 interface ISampleGrabberCB : public IUnknown
233 {
234     virtual HRESULT STDMETHODCALLTYPE SampleCB(
235         double SampleTime,
236         IMediaSample *pSample) = 0;
237
238     virtual HRESULT STDMETHODCALLTYPE BufferCB(
239         double SampleTime,
240         BYTE *pBuffer,
241         LONG BufferLen) = 0;
242
243     virtual ~ISampleGrabberCB() {}
244 };
245
246 interface ISampleGrabber : public IUnknown
247 {
248     virtual HRESULT STDMETHODCALLTYPE SetOneShot(
249         BOOL OneShot) = 0;
250
251     virtual HRESULT STDMETHODCALLTYPE SetMediaType(
252         const AM_MEDIA_TYPE *pType) = 0;
253
254     virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
255         AM_MEDIA_TYPE *pType) = 0;
256
257     virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
258         BOOL BufferThem) = 0;
259
260     virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
261         LONG *pBufferSize,
262         LONG *pBuffer) = 0;
263
264     virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
265         IMediaSample **ppSample) = 0;
266
267     virtual HRESULT STDMETHODCALLTYPE SetCallback(
268         ISampleGrabberCB *pCallback,
269         LONG WhichMethodToCallback) = 0;
270
271     virtual ~ISampleGrabber() {}
272 };
273
274 #ifndef HEADER
275 #define HEADER(p) (&(((VIDEOINFOHEADER*)(p))->bmiHeader))
276 #endif
277
278 //Example Usage
279 /*
280     //create a videoInput object
281     videoInput VI;
282
283     //Prints out a list of available devices and returns num of devices found
284     int numDevices = VI.listDevices();
285
286     int device1 = 0;  //this could be any deviceID that shows up in listDevices
287     int device2 = 1;  //this could be any deviceID that shows up in listDevices
288
289     //if you want to capture at a different frame rate (default is 30)
290     //specify it here, you are not guaranteed to get this fps though.
291     //VI.setIdealFramerate(dev, 60);
292
293     //setup the first device - there are a number of options:
294
295     VI.setupDevice(device1);                           //setup the first device with the default settings
296     //VI.setupDevice(device1, VI_COMPOSITE);           //or setup device with specific connection type
297     //VI.setupDevice(device1, 320, 240);               //or setup device with specified video size
298     //VI.setupDevice(device1, 320, 240, VI_COMPOSITE); //or setup device with video size and connection type
299
300     //VI.setFormat(device1, VI_NTSC_M);                //if your card doesn't remember what format it should be
301                                                        //call this with the appropriate format listed above
302                                                        //NOTE: must be called after setupDevice!
303
304     //optionally setup a second (or third, fourth ...) device - same options as above
305     VI.setupDevice(device2);
306
307     //As requested width and height can not always be accomodated
308     //make sure to check the size once the device is setup
309
310     int width   = VI.getWidth(device1);
311     int height  = VI.getHeight(device1);
312     int size    = VI.getSize(device1);
313
314     unsigned char * yourBuffer1 = new unsigned char[size];
315     unsigned char * yourBuffer2 = new unsigned char[size];
316
317     //to get the data from the device first check if the data is new
318     if(VI.isFrameNew(device1)){
319         VI.getPixels(device1, yourBuffer1, false, false);   //fills pixels as a BGR (for openCV) unsigned char array - no flipping
320         VI.getPixels(device1, yourBuffer2, true, true);     //fills pixels as a RGB (for openGL) unsigned char array - flipping!
321     }
322
323     //same applies to device2 etc
324
325     //to get a settings dialog for the device
326     VI.showSettingsWindow(device1);
327
328
329     //Shut down devices properly
330     VI.stopDevice(device1);
331     VI.stopDevice(device2);
332 */
333
334
335 //////////////////////////////////////   VARS AND DEFS   //////////////////////////////////
336
337
338 //STUFF YOU CAN CHANGE
339
340 //change for verbose debug info
341 static bool verbose = true;
342
343 //if you need VI to use multi threaded com
344 //#define VI_COM_MULTI_THREADED
345
346 //STUFF YOU DON'T CHANGE
347
348 //videoInput defines
349 #define VI_VERSION      0.1995
350 #define VI_MAX_CAMERAS  20
351 #define VI_NUM_TYPES    20 //MGB
352 #define VI_NUM_FORMATS  18 //DON'T TOUCH
353
354 //defines for setPhyCon - tuner is not as well supported as composite and s-video
355 #define VI_COMPOSITE 0
356 #define VI_S_VIDEO   1
357 #define VI_TUNER     2
358 #define VI_USB       3
359 #define VI_1394      4
360
361 //defines for formats
362 #define VI_NTSC_M   0
363 #define VI_PAL_B    1
364 #define VI_PAL_D    2
365 #define VI_PAL_G    3
366 #define VI_PAL_H    4
367 #define VI_PAL_I    5
368 #define VI_PAL_M    6
369 #define VI_PAL_N    7
370 #define VI_PAL_NC   8
371 #define VI_SECAM_B  9
372 #define VI_SECAM_D  10
373 #define VI_SECAM_G  11
374 #define VI_SECAM_H  12
375 #define VI_SECAM_K  13
376 #define VI_SECAM_K1 14
377 #define VI_SECAM_L  15
378 #define VI_NTSC_M_J 16
379 #define VI_NTSC_433 17
380
381
382 //allows us to directShow classes here with the includes in the cpp
383 struct ICaptureGraphBuilder2;
384 struct IGraphBuilder;
385 struct IBaseFilter;
386 struct IAMCrossbar;
387 struct IMediaControl;
388 struct ISampleGrabber;
389 struct IMediaEventEx;
390 struct IAMStreamConfig;
391 struct _AMMediaType;
392 class SampleGrabberCallback;
393 typedef _AMMediaType AM_MEDIA_TYPE;
394
395 //keeps track of how many instances of VI are being used
396 //don't touch
397 //static int comInitCount = 0;
398
399
400 ////////////////////////////////////////   VIDEO DEVICE   ///////////////////////////////////
401
402 class videoDevice{
403
404
405     public:
406
407         videoDevice();
408         void setSize(int w, int h);
409         void NukeDownstream(IBaseFilter *pBF);
410         void destroyGraph();
411         ~videoDevice();
412
413         int videoSize;
414         int width;
415         int height;
416
417         int tryWidth;
418         int tryHeight;
419         GUID tryVideoType;
420
421         ICaptureGraphBuilder2 *pCaptureGraph;    // Capture graph builder object
422         IGraphBuilder *pGraph;                    // Graph builder object
423         IMediaControl *pControl;                // Media control object
424         IBaseFilter *pVideoInputFilter;          // Video Capture filter
425         IBaseFilter *pGrabberF;
426         IBaseFilter * pDestFilter;
427         IAMStreamConfig *streamConf;
428         ISampleGrabber * pGrabber;                // Grabs frame
429         AM_MEDIA_TYPE * pAmMediaType;
430
431         IMediaEventEx * pMediaEvent;
432
433         GUID videoType;
434         long formatType;
435
436         SampleGrabberCallback * sgCallback;
437
438         bool tryDiffSize;
439         bool useCrossbar;
440         bool readyToCapture;
441         bool sizeSet;
442         bool setupStarted;
443         bool specificFormat;
444         bool autoReconnect;
445         int  nFramesForReconnect;
446         unsigned long nFramesRunning;
447         int  connection;
448         int  storeConn;
449         int  myID;
450         long requestedFrameTime; //ie fps
451
452         char  nDeviceName[255];
453         WCHAR wDeviceName[255];
454
455         unsigned char * pixels;
456         char * pBuffer;
457
458 };
459
460
461
462
463 //////////////////////////////////////   VIDEO INPUT   /////////////////////////////////////
464
465
466
467 class videoInput{
468
469     public:
470         videoInput();
471         ~videoInput();
472
473         //turns off console messages - default is to print messages
474         static void setVerbose(bool _verbose);
475
476         //Functions in rough order they should be used.
477         static int listDevices(bool silent = false);
478
479         //needs to be called after listDevices - otherwise returns NULL
480         static char * getDeviceName(int deviceID);
481
482         //choose to use callback based capture - or single threaded
483         void setUseCallback(bool useCallback);
484
485         //call before setupDevice
486         //directshow will try and get the closest possible framerate to what is requested
487         void setIdealFramerate(int deviceID, int idealFramerate);
488
489         //some devices will stop delivering frames after a while - this method gives you the option to try and reconnect
490         //to a device if videoInput detects that a device has stopped delivering frames.
491         //you MUST CALL isFrameNew every app loop for this to have any effect
492         void setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect);
493
494         //Choose one of these five to setup your device
495         bool setupDevice(int deviceID);
496         bool setupDevice(int deviceID, int w, int h);
497         bool setupDeviceFourcc(int deviceID, int w, int h,int fourcc);
498
499         //These two are only for capture cards
500         //USB and Firewire cameras souldn't specify connection
501         bool setupDevice(int deviceID, int connection);
502         bool setupDevice(int deviceID, int w, int h, int connection);
503
504         bool setFourcc(int deviceNumber, int fourcc);
505
506         //If you need to you can set your NTSC/PAL/SECAM
507         //preference here. if it is available it will be used.
508         //see #defines above for available formats - eg VI_NTSC_M or VI_PAL_B
509         //should be called after setupDevice
510         //can be called multiple times
511         bool setFormat(int deviceNumber, int format);
512
513         //Tells you when a new frame has arrived - you should call this if you have specified setAutoReconnectOnFreeze to true
514         bool isFrameNew(int deviceID);
515
516         bool isDeviceSetup(int deviceID);
517
518         //Returns the pixels - flipRedAndBlue toggles RGB/BGR flipping - and you can flip the image too
519         unsigned char * getPixels(int deviceID, bool flipRedAndBlue = true, bool flipImage = false);
520
521         //Or pass in a buffer for getPixels to fill returns true if successful.
522         bool getPixels(int id, unsigned char * pixels, bool flipRedAndBlue = true, bool flipImage = false);
523
524         //Launches a pop up settings window
525         //For some reason in GLUT you have to call it twice each time.
526         void showSettingsWindow(int deviceID);
527
528         //Manual control over settings thanks.....
529         //These are experimental for now.
530         bool setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false);
531         bool setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags = 0);
532         bool getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue);
533
534         bool setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false);
535         bool setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags = 0);
536         bool getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue);
537
538         //bool setVideoSettingCam(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false);
539
540         //get width, height and number of pixels
541         int  getWidth(int deviceID);
542         int  getHeight(int deviceID);
543         int  getSize(int deviceID);
544         int  getFourcc(int deviceID);
545         double getFPS(int deviceID);
546
547         //completely stops and frees a device
548         void stopDevice(int deviceID);
549
550         //as above but then sets it up with same settings
551         bool restartDevice(int deviceID);
552
553         //number of devices available
554         int  devicesFound;
555
556         // mapping from OpenCV CV_CAP_PROP to videoinput/dshow properties
557         int getVideoPropertyFromCV(int cv_property);
558         int getCameraPropertyFromCV(int cv_property);
559
560     private:
561         void setPhyCon(int deviceID, int conn);
562         void setAttemptCaptureSize(int deviceID, int w, int h,GUID mediaType=MEDIASUBTYPE_RGB24);
563         bool setup(int deviceID);
564         void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip);
565         int  start(int deviceID, videoDevice * VD);
566         int  getDeviceCount();
567         void getMediaSubtypeAsString(GUID type, char * typeAsString);
568         GUID *getMediaSubtypeFromFourcc(int fourcc);
569         int    getFourccFromMediaSubtype(GUID type);
570
571         void getVideoPropertyAsString(int prop, char * propertyAsString);
572         void getCameraPropertyAsString(int prop, char * propertyAsString);
573
574         HRESULT getDevice(IBaseFilter **pSrcFilter, int deviceID, WCHAR * wDeviceName, char * nDeviceName);
575         static HRESULT ShowFilterPropertyPages(IBaseFilter *pFilter);
576         static HRESULT ShowStreamPropertyPages(IAMStreamConfig  *pStream);
577
578         HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath);
579         HRESULT routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode);
580
581         //don't touch
582         static bool comInit();
583         static bool comUnInit();
584
585         int  connection;
586         int  callbackSetCount;
587         bool bCallback;
588
589         GUID CAPTURE_MODE;
590
591         //Extra video subtypes
592         GUID MEDIASUBTYPE_Y800;
593         GUID MEDIASUBTYPE_Y8;
594         GUID MEDIASUBTYPE_GREY;
595
596         videoDevice * VDList[VI_MAX_CAMERAS];
597         GUID mediaSubtypes[VI_NUM_TYPES];
598         long formatTypes[VI_NUM_FORMATS];
599
600         static void __cdecl basicThread(void * objPtr);
601
602         static char deviceNames[VI_MAX_CAMERAS][255];
603
604 };
605
606 ///////////////////////////  HANDY FUNCTIONS  /////////////////////////////
607
608 static void MyFreeMediaType(AM_MEDIA_TYPE& mt){
609     if (mt.cbFormat != 0)
610     {
611         CoTaskMemFree((PVOID)mt.pbFormat);
612         mt.cbFormat = 0;
613         mt.pbFormat = NULL;
614     }
615     if (mt.pUnk != NULL)
616     {
617         // Unecessary because pUnk should not be used, but safest.
618         mt.pUnk->Release();
619         mt.pUnk = NULL;
620     }
621 }
622
623 static void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
624 {
625     if (pmt != NULL)
626     {
627         MyFreeMediaType(*pmt);
628         CoTaskMemFree(pmt);
629     }
630 }
631
632 //////////////////////////////  CALLBACK  ////////////////////////////////
633
634 //Callback class
635 class SampleGrabberCallback : public ISampleGrabberCB{
636 public:
637
638     //------------------------------------------------
639     SampleGrabberCallback(){
640         InitializeCriticalSection(&critSection);
641         freezeCheck = 0;
642
643
644         bufferSetup         = false;
645         newFrame            = false;
646         latestBufferLength  = 0;
647
648         hEvent = CreateEvent(NULL, true, false, NULL);
649     }
650
651
652     //------------------------------------------------
653     virtual ~SampleGrabberCallback(){
654         ptrBuffer = NULL;
655         DeleteCriticalSection(&critSection);
656         CloseHandle(hEvent);
657         if(bufferSetup){
658             delete[] pixels;
659         }
660     }
661
662
663     //------------------------------------------------
664     bool setupBuffer(int numBytesIn){
665         if(bufferSetup){
666             return false;
667         }else{
668             numBytes            = numBytesIn;
669             pixels              = new unsigned char[numBytes];
670             bufferSetup         = true;
671             newFrame            = false;
672             latestBufferLength  = 0;
673         }
674         return true;
675     }
676
677
678     //------------------------------------------------
679     STDMETHODIMP_(ULONG) AddRef() { return 1; }
680     STDMETHODIMP_(ULONG) Release() { return 2; }
681
682
683     //------------------------------------------------
684     STDMETHODIMP QueryInterface(REFIID, void **ppvObject){
685         *ppvObject = static_cast<ISampleGrabberCB*>(this);
686         return S_OK;
687     }
688
689
690     //This method is meant to have less overhead
691     //------------------------------------------------
692     STDMETHODIMP SampleCB(double , IMediaSample *pSample){
693         if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) return S_OK;
694
695         HRESULT hr = pSample->GetPointer(&ptrBuffer);
696
697         if(hr == S_OK){
698             latestBufferLength = pSample->GetActualDataLength();
699               if(latestBufferLength == numBytes){
700                 EnterCriticalSection(&critSection);
701                       memcpy(pixels, ptrBuffer, latestBufferLength);
702                     newFrame    = true;
703                     freezeCheck = 1;
704                 LeaveCriticalSection(&critSection);
705                 SetEvent(hEvent);
706             }else{
707                 printf("ERROR: SampleCB() - buffer sizes do not match\n");
708             }
709         }
710
711         return S_OK;
712     }
713
714
715     //This method is meant to have more overhead
716     STDMETHODIMP BufferCB(double, BYTE *, long){
717         return E_NOTIMPL;
718     }
719
720     int freezeCheck;
721
722     int latestBufferLength;
723     int numBytes;
724     bool newFrame;
725     bool bufferSetup;
726     unsigned char * pixels;
727     unsigned char * ptrBuffer;
728     CRITICAL_SECTION critSection;
729     HANDLE hEvent;
730 };
731
732
733 //////////////////////////////  VIDEO DEVICE  ////////////////////////////////
734
735 // ----------------------------------------------------------------------
736 //    Should this class also be the callback?
737 //
738 // ----------------------------------------------------------------------
739
740 videoDevice::videoDevice(){
741
742      pCaptureGraph      = NULL;    // Capture graph builder object
743      pGraph             = NULL;    // Graph builder object
744      pControl           = NULL;    // Media control object
745      pVideoInputFilter  = NULL; // Video Capture filter
746      pGrabber           = NULL; // Grabs frame
747      pDestFilter        = NULL; // Null Renderer Filter
748      pGrabberF          = NULL; // Grabber Filter
749      pMediaEvent        = NULL;
750      streamConf         = NULL;
751      pAmMediaType       = NULL;
752
753      //This is our callback class that processes the frame.
754      sgCallback           = new SampleGrabberCallback();
755      sgCallback->newFrame = false;
756
757      //Default values for capture type
758      videoType          = MEDIASUBTYPE_RGB24;
759      connection         = PhysConn_Video_Composite;
760      storeConn          = 0;
761
762      videoSize          = 0;
763      width              = 0;
764      height             = 0;
765
766      tryWidth           = 640;
767      tryHeight          = 480;
768      tryVideoType = MEDIASUBTYPE_RGB24;
769      nFramesForReconnect= 10000;
770      nFramesRunning     = 0;
771      myID               = -1;
772
773      tryDiffSize        = true;
774      useCrossbar        = false;
775      readyToCapture     = false;
776      sizeSet            = false;
777      setupStarted       = false;
778      specificFormat     = false;
779      autoReconnect      = false;
780      requestedFrameTime = -1;
781
782      memset(wDeviceName, 0, sizeof(WCHAR) * 255);
783      memset(nDeviceName, 0, sizeof(char) * 255);
784
785 }
786
787
788 // ----------------------------------------------------------------------
789 //    The only place we are doing new
790 //
791 // ----------------------------------------------------------------------
792
793 void videoDevice::setSize(int w, int h){
794     if(sizeSet){
795         if(verbose)printf("SETUP: Error device size should not be set more than once \n");
796     }
797     else
798     {
799         width               = w;
800         height              = h;
801         videoSize           = w*h*3;
802         sizeSet             = true;
803         pixels              = new unsigned char[videoSize];
804         pBuffer             = new char[videoSize];
805
806         memset(pixels, 0 , videoSize);
807         sgCallback->setupBuffer(videoSize);
808
809     }
810 }
811
812
813 // ----------------------------------------------------------------------
814 //    Borrowed from the SDK, use it to take apart the graph from
815 //  the capture device downstream to the null renderer
816 // ----------------------------------------------------------------------
817
818 void videoDevice::NukeDownstream(IBaseFilter *pBF){
819     IPin *pP, *pTo;
820     ULONG u;
821     IEnumPins *pins = NULL;
822     PIN_INFO pininfo;
823     HRESULT hr = pBF->EnumPins(&pins);
824     pins->Reset();
825     while (hr == NOERROR)
826     {
827         hr = pins->Next(1, &pP, &u);
828         if (hr == S_OK && pP)
829         {
830             pP->ConnectedTo(&pTo);
831             if (pTo)
832             {
833                 hr = pTo->QueryPinInfo(&pininfo);
834                 if (hr == NOERROR)
835                 {
836                     if (pininfo.dir == PINDIR_INPUT)
837                     {
838                         NukeDownstream(pininfo.pFilter);
839                         pGraph->Disconnect(pTo);
840                         pGraph->Disconnect(pP);
841                         pGraph->RemoveFilter(pininfo.pFilter);
842                     }
843                     pininfo.pFilter->Release();
844                     pininfo.pFilter = NULL;
845                 }
846                 pTo->Release();
847             }
848             pP->Release();
849         }
850     }
851     if (pins) pins->Release();
852 }
853
854
855 // ----------------------------------------------------------------------
856 //    Also from SDK
857 // ----------------------------------------------------------------------
858
859 void videoDevice::destroyGraph(){
860     HRESULT hr = 0;
861      //int FuncRetval=0;
862      //int NumFilters=0;
863
864     int i = 0;
865     while (hr == NOERROR)
866     {
867         IEnumFilters * pEnum = 0;
868         ULONG cFetched;
869
870         // We must get the enumerator again every time because removing a filter from the graph
871         // invalidates the enumerator. We always get only the first filter from each enumerator.
872         hr = pGraph->EnumFilters(&pEnum);
873         if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->EnumFilters() failed. \n"); return; }
874
875         IBaseFilter * pFilter = NULL;
876         if (pEnum->Next(1, &pFilter, &cFetched) == S_OK)
877         {
878             FILTER_INFO FilterInfo;
879             memset(&FilterInfo, 0, sizeof(FilterInfo));
880             hr = pFilter->QueryFilterInfo(&FilterInfo);
881             FilterInfo.pGraph->Release();
882
883             int count = 0;
884             char buffer[255];
885             memset(buffer, 0, 255 * sizeof(char));
886
887             while( FilterInfo.achName[count] != 0x00 )
888             {
889                 buffer[count] = (char)FilterInfo.achName[count];
890                 count++;
891             }
892
893             if(verbose)printf("SETUP: removing filter %s...\n", buffer);
894             hr = pGraph->RemoveFilter(pFilter);
895             if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->RemoveFilter() failed. \n"); return; }
896             if(verbose)printf("SETUP: filter removed %s  \n",buffer);
897
898             pFilter->Release();
899             pFilter = NULL;
900         }
901         else break;
902         pEnum->Release();
903         pEnum = NULL;
904         i++;
905     }
906
907  return;
908 }
909
910
911 // ----------------------------------------------------------------------
912 // Our deconstructor, attempts to tear down graph and release filters etc
913 // Does checking to make sure it only is freeing if it needs to
914 // Probably could be a lot cleaner! :)
915 // ----------------------------------------------------------------------
916
917 videoDevice::~videoDevice(){
918
919     if(setupStarted){ if(verbose)printf("\nSETUP: Disconnecting device %i\n", myID); }
920     else{
921         if(sgCallback){
922             sgCallback->Release();
923             delete sgCallback;
924         }
925         return;
926     }
927
928     HRESULT HR = NOERROR;
929
930     //Stop the callback and free it
931     if( (sgCallback) && (pGrabber) )
932     {
933         pGrabber->SetCallback(NULL, 1);
934         if(verbose)printf("SETUP: freeing Grabber Callback\n");
935         sgCallback->Release();
936
937         //delete our pixels
938         if(sizeSet){
939              delete[] pixels;
940              delete[] pBuffer;
941         }
942
943         delete sgCallback;
944     }
945
946     //Check to see if the graph is running, if so stop it.
947      if( (pControl) )
948     {
949         HR = pControl->Pause();
950         if (FAILED(HR)) if(verbose)printf("ERROR - Could not pause pControl\n");
951
952         HR = pControl->Stop();
953         if (FAILED(HR)) if(verbose)printf("ERROR - Could not stop pControl\n");
954     }
955
956     //Disconnect filters from capture device
957     if( (pVideoInputFilter) )NukeDownstream(pVideoInputFilter);
958
959     //Release and zero pointers to our filters etc
960     if( (pDestFilter) ){        if(verbose)printf("SETUP: freeing Renderer \n");
961                                 (pDestFilter)->Release();
962                                 (pDestFilter) = 0;
963     }
964     if( (pVideoInputFilter) ){  if(verbose)printf("SETUP: freeing Capture Source \n");
965                                 (pVideoInputFilter)->Release();
966                                 (pVideoInputFilter) = 0;
967     }
968     if( (pGrabberF) ){          if(verbose)printf("SETUP: freeing Grabber Filter  \n");
969                                 (pGrabberF)->Release();
970                                 (pGrabberF) = 0;
971     }
972     if( (pGrabber) ){           if(verbose)printf("SETUP: freeing Grabber  \n");
973                                 (pGrabber)->Release();
974                                 (pGrabber) = 0;
975     }
976     if( (pControl) ){           if(verbose)printf("SETUP: freeing Control   \n");
977                                 (pControl)->Release();
978                                 (pControl) = 0;
979     }
980     if( (pMediaEvent) ){        if(verbose)printf("SETUP: freeing Media Event  \n");
981                                 (pMediaEvent)->Release();
982                                 (pMediaEvent) = 0;
983     }
984     if( (streamConf) ){         if(verbose)printf("SETUP: freeing Stream  \n");
985                                 (streamConf)->Release();
986                                 (streamConf) = 0;
987     }
988
989     if( (pAmMediaType) ){       if(verbose)printf("SETUP: freeing Media Type  \n");
990                                 MyDeleteMediaType(pAmMediaType);
991     }
992
993     if((pMediaEvent)){
994             if(verbose)printf("SETUP: freeing Media Event  \n");
995             (pMediaEvent)->Release();
996             (pMediaEvent) = 0;
997     }
998
999     //Destroy the graph
1000     if( (pGraph) )destroyGraph();
1001
1002     //Release and zero our capture graph and our main graph
1003     if( (pCaptureGraph) ){      if(verbose)printf("SETUP: freeing Capture Graph \n");
1004                                 (pCaptureGraph)->Release();
1005                                 (pCaptureGraph) = 0;
1006     }
1007     if( (pGraph) ){             if(verbose)printf("SETUP: freeing Main Graph \n");
1008                                 (pGraph)->Release();
1009                                 (pGraph) = 0;
1010     }
1011
1012     //delete our pointers
1013     delete pDestFilter;
1014     delete pVideoInputFilter;
1015     delete pGrabberF;
1016     delete pGrabber;
1017     delete pControl;
1018     delete streamConf;
1019     delete pMediaEvent;
1020     delete pCaptureGraph;
1021     delete pGraph;
1022
1023     if(verbose)printf("SETUP: Device %i disconnected and freed\n\n",myID);
1024 }
1025
1026
1027 //////////////////////////////  VIDEO INPUT  ////////////////////////////////
1028 ////////////////////////////  PUBLIC METHODS  ///////////////////////////////
1029
1030
1031 // ----------------------------------------------------------------------
1032 // Constructor - creates instances of videoDevice and adds the various
1033 // media subtypes to check.
1034 // ----------------------------------------------------------------------
1035
1036 videoInput::videoInput(){
1037     //start com
1038     comInit();
1039
1040     devicesFound         = 0;
1041     callbackSetCount     = 0;
1042     bCallback            = true;
1043
1044     //setup a max no of device objects
1045     for(int i=0; i<VI_MAX_CAMERAS; i++)  VDList[i] = new videoDevice();
1046
1047     if(verbose)printf("\n***** VIDEOINPUT LIBRARY - %2.04f - TFW07 *****\n\n",VI_VERSION);
1048
1049     //added for the pixelink firewire camera
1050      //MEDIASUBTYPE_Y800 = (GUID)FOURCCMap(FCC('Y800'));
1051      //MEDIASUBTYPE_Y8   = (GUID)FOURCCMap(FCC('Y8'));
1052      //MEDIASUBTYPE_GREY = (GUID)FOURCCMap(FCC('GREY'));
1053
1054     //The video types we support
1055     //in order of preference
1056
1057     mediaSubtypes[0]     = MEDIASUBTYPE_RGB24;
1058     mediaSubtypes[1]     = MEDIASUBTYPE_RGB32;
1059     mediaSubtypes[2]     = MEDIASUBTYPE_RGB555;
1060     mediaSubtypes[3]     = MEDIASUBTYPE_RGB565;
1061     mediaSubtypes[4]     = MEDIASUBTYPE_YUY2;
1062     mediaSubtypes[5]     = MEDIASUBTYPE_YVYU;
1063     mediaSubtypes[6]     = MEDIASUBTYPE_YUYV;
1064     mediaSubtypes[7]     = MEDIASUBTYPE_IYUV;
1065     mediaSubtypes[8]     = MEDIASUBTYPE_UYVY;
1066     mediaSubtypes[9]     = MEDIASUBTYPE_YV12;
1067     mediaSubtypes[10]    = MEDIASUBTYPE_YVU9;
1068     mediaSubtypes[11]    = MEDIASUBTYPE_Y411;
1069     mediaSubtypes[12]    = MEDIASUBTYPE_Y41P;
1070     mediaSubtypes[13]    = MEDIASUBTYPE_Y211;
1071     mediaSubtypes[14]    = MEDIASUBTYPE_AYUV;
1072     mediaSubtypes[15]    = MEDIASUBTYPE_MJPG; // MGB
1073
1074     //non standard
1075     mediaSubtypes[16]    = MEDIASUBTYPE_Y800;
1076     mediaSubtypes[17]    = MEDIASUBTYPE_Y8;
1077     mediaSubtypes[18]    = MEDIASUBTYPE_GREY;
1078     mediaSubtypes[19]    = MEDIASUBTYPE_I420;
1079
1080     //The video formats we support
1081     formatTypes[VI_NTSC_M]      = AnalogVideo_NTSC_M;
1082     formatTypes[VI_NTSC_M_J]    = AnalogVideo_NTSC_M_J;
1083     formatTypes[VI_NTSC_433]    = AnalogVideo_NTSC_433;
1084
1085     formatTypes[VI_PAL_B]       = AnalogVideo_PAL_B;
1086     formatTypes[VI_PAL_D]       = AnalogVideo_PAL_D;
1087     formatTypes[VI_PAL_G]       = AnalogVideo_PAL_G;
1088     formatTypes[VI_PAL_H]       = AnalogVideo_PAL_H;
1089     formatTypes[VI_PAL_I]       = AnalogVideo_PAL_I;
1090     formatTypes[VI_PAL_M]       = AnalogVideo_PAL_M;
1091     formatTypes[VI_PAL_N]       = AnalogVideo_PAL_N;
1092     formatTypes[VI_PAL_NC]      = AnalogVideo_PAL_N_COMBO;
1093
1094     formatTypes[VI_SECAM_B]     = AnalogVideo_SECAM_B;
1095     formatTypes[VI_SECAM_D]     = AnalogVideo_SECAM_D;
1096     formatTypes[VI_SECAM_G]     = AnalogVideo_SECAM_G;
1097     formatTypes[VI_SECAM_H]     = AnalogVideo_SECAM_H;
1098     formatTypes[VI_SECAM_K]     = AnalogVideo_SECAM_K;
1099     formatTypes[VI_SECAM_K1]    = AnalogVideo_SECAM_K1;
1100     formatTypes[VI_SECAM_L]     = AnalogVideo_SECAM_L;
1101
1102 }
1103
1104
1105 // ----------------------------------------------------------------------
1106 // static - set whether messages get printed to console or not
1107 //
1108 // ----------------------------------------------------------------------
1109
1110 void videoInput::setVerbose(bool _verbose){
1111     verbose = _verbose;
1112 }
1113
1114 // ----------------------------------------------------------------------
1115 // change to use callback or regular capture
1116 // callback tells you when a new frame has arrived
1117 // but non-callback won't - but is single threaded
1118 // ----------------------------------------------------------------------
1119 void videoInput::setUseCallback(bool useCallback){
1120     if(callbackSetCount == 0){
1121         bCallback = useCallback;
1122         callbackSetCount = 1;
1123     }else{
1124         printf("ERROR: setUseCallback can only be called before setup\n");
1125     }
1126 }
1127
1128 // ----------------------------------------------------------------------
1129 // Set the requested framerate - no guarantee you will get this
1130 //
1131 // ----------------------------------------------------------------------
1132
1133 void videoInput::setIdealFramerate(int deviceNumber, int idealFramerate){
1134     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return;
1135
1136     if( idealFramerate > 0 ){
1137         VDList[deviceNumber]->requestedFrameTime = (unsigned long)(10000000 / idealFramerate);
1138     }
1139 }
1140
1141
1142 // ----------------------------------------------------------------------
1143 // Set the requested framerate - no guarantee you will get this
1144 //
1145 // ----------------------------------------------------------------------
1146
1147 void videoInput::setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect){
1148     if(deviceNumber >= VI_MAX_CAMERAS) return;
1149
1150     VDList[deviceNumber]->autoReconnect            = doReconnect;
1151     VDList[deviceNumber]->nFramesForReconnect    = numMissedFramesBeforeReconnect;
1152
1153 }
1154
1155
1156 // ----------------------------------------------------------------------
1157 // Setup a device with the default settings
1158 //
1159 // ----------------------------------------------------------------------
1160
1161 bool videoInput::setupDevice(int deviceNumber){
1162     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1163
1164     if(setup(deviceNumber))return true;
1165     return false;
1166 }
1167
1168
1169 // ----------------------------------------------------------------------
1170 // Setup a device with the default size but specify input type
1171 //
1172 // ----------------------------------------------------------------------
1173
1174 bool videoInput::setupDevice(int deviceNumber, int _connection){
1175     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1176
1177     setPhyCon(deviceNumber, _connection);
1178     if(setup(deviceNumber))return true;
1179     return false;
1180 }
1181
1182
1183 // ----------------------------------------------------------------------
1184 // Setup a device with the default connection but specify size
1185 //
1186 // ----------------------------------------------------------------------
1187
1188 bool videoInput::setupDevice(int deviceNumber, int w, int h){
1189     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1190
1191     setAttemptCaptureSize(deviceNumber,w,h);
1192     if(setup(deviceNumber))return true;
1193     return false;
1194 }
1195
1196 // ----------------------------------------------------------------------
1197 // Setup a device with the default connection but specify size and image format
1198 //
1199 // Note:
1200 // Need a new name for this since signature clashes with ",int connection)"
1201 // ----------------------------------------------------------------------
1202
1203 bool videoInput::setupDeviceFourcc(int deviceNumber, int w, int h,int fourcc){
1204     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1205
1206     if ( fourcc != -1 ) {
1207         GUID *mediaType = getMediaSubtypeFromFourcc(fourcc);
1208         if ( mediaType ) {
1209             setAttemptCaptureSize(deviceNumber,w,h,*mediaType);
1210         }
1211     } else {
1212         setAttemptCaptureSize(deviceNumber,w,h);
1213     }
1214     if(setup(deviceNumber))return true;
1215     return false;
1216 }
1217
1218
1219 // ----------------------------------------------------------------------
1220 // Setup a device with specific size and connection
1221 //
1222 // ----------------------------------------------------------------------
1223
1224 bool videoInput::setupDevice(int deviceNumber, int w, int h, int _connection){
1225     if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1226
1227     setAttemptCaptureSize(deviceNumber,w,h);
1228     setPhyCon(deviceNumber, _connection);
1229     if(setup(deviceNumber))return true;
1230     return false;
1231 }
1232
1233
1234 // ----------------------------------------------------------------------
1235 // Setup the default video format of the device
1236 // Must be called after setup!
1237 // See #define formats in header file (eg VI_NTSC_M )
1238 //
1239 // ----------------------------------------------------------------------
1240
1241 bool videoInput::setFormat(int deviceNumber, int format){
1242     if(deviceNumber >= VI_MAX_CAMERAS || !VDList[deviceNumber]->readyToCapture) return false;
1243
1244     bool returnVal = false;
1245
1246     if(format >= 0 && format < VI_NUM_FORMATS){
1247         VDList[deviceNumber]->formatType = formatTypes[format];
1248         VDList[deviceNumber]->specificFormat = true;
1249
1250         if(VDList[deviceNumber]->specificFormat){
1251
1252             HRESULT hr = getDevice(&VDList[deviceNumber]->pVideoInputFilter, deviceNumber, VDList[deviceNumber]->wDeviceName, VDList[deviceNumber]->nDeviceName);
1253             if(hr != S_OK){
1254                 return false;
1255             }
1256
1257             IAMAnalogVideoDecoder *pVideoDec = NULL;
1258                hr = VDList[deviceNumber]->pCaptureGraph->FindInterface(NULL, &MEDIATYPE_Video, VDList[deviceNumber]->pVideoInputFilter, IID_IAMAnalogVideoDecoder, (void **)&pVideoDec);
1259
1260
1261             //in case the settings window some how freed them first
1262             if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter->Release();
1263             if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter = NULL;
1264
1265             if(FAILED(hr)){
1266                 printf("SETUP: couldn't set requested format\n");
1267             }else{
1268                 long lValue = 0;
1269                 hr = pVideoDec->get_AvailableTVFormats(&lValue);
1270                 if( SUCCEEDED(hr) && (lValue & VDList[deviceNumber]->formatType) )
1271                    {
1272                        hr = pVideoDec->put_TVFormat(VDList[deviceNumber]->formatType);
1273                     if( FAILED(hr) ){
1274                         printf("SETUP: couldn't set requested format\n");
1275                     }else{
1276                         returnVal = true;
1277                     }
1278                    }
1279
1280                 pVideoDec->Release();
1281                 pVideoDec = NULL;
1282             }
1283         }
1284     }
1285
1286     return returnVal;
1287 }
1288
1289 // ----------------------------------------------------------------------
1290 // Our static function for returning device names - thanks Peter!
1291 // Must call listDevices first.
1292 //
1293 // ----------------------------------------------------------------------
1294 char videoInput::deviceNames[VI_MAX_CAMERAS][255]={{0}};
1295
1296 char * videoInput::getDeviceName(int deviceID){
1297     if( deviceID >= VI_MAX_CAMERAS ){
1298         return NULL;
1299     }
1300     return deviceNames[deviceID];
1301 }
1302
1303
1304 // ----------------------------------------------------------------------
1305 // Our static function for finding num devices available etc
1306 //
1307 // ----------------------------------------------------------------------
1308
1309 int videoInput::listDevices(bool silent){
1310
1311     //COM Library Intialization
1312     comInit();
1313
1314     if(!silent)printf("\nVIDEOINPUT SPY MODE!\n\n");
1315
1316
1317     ICreateDevEnum *pDevEnum = NULL;
1318     IEnumMoniker *pEnum = NULL;
1319     int deviceCounter = 0;
1320
1321     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
1322         CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
1323         reinterpret_cast<void**>(&pDevEnum));
1324
1325
1326     if (SUCCEEDED(hr))
1327     {
1328         // Create an enumerator for the video capture category.
1329         hr = pDevEnum->CreateClassEnumerator(
1330             CLSID_VideoInputDeviceCategory,
1331             &pEnum, 0);
1332
1333        if(hr == S_OK){
1334
1335              if(!silent)printf("SETUP: Looking For Capture Devices\n");
1336             IMoniker *pMoniker = NULL;
1337
1338             while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
1339
1340                 IPropertyBag *pPropBag;
1341                 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
1342                     (void**)(&pPropBag));
1343
1344                 if (FAILED(hr)){
1345                     pMoniker->Release();
1346                     continue;  // Skip this one, maybe the next one will work.
1347                 }
1348
1349
1350                  // Find the description or friendly name.
1351                 VARIANT varName;
1352                 VariantInit(&varName);
1353                 hr = pPropBag->Read(L"Description", &varName, 0);
1354
1355                 if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);
1356
1357                 if (SUCCEEDED(hr)){
1358
1359                     hr = pPropBag->Read(L"FriendlyName", &varName, 0);
1360
1361                     int count = 0;
1362                     int maxLen = sizeof(deviceNames[0])/sizeof(deviceNames[0][0]) - 2;
1363                     while( varName.bstrVal[count] != 0x00 && count < maxLen) {
1364                         deviceNames[deviceCounter][count] = (char)varName.bstrVal[count];
1365                         count++;
1366                     }
1367                     deviceNames[deviceCounter][count] = 0;
1368
1369                     if(!silent)printf("SETUP: %i) %s \n",deviceCounter, deviceNames[deviceCounter]);
1370                 }
1371
1372                 pPropBag->Release();
1373                 pPropBag = NULL;
1374
1375                 pMoniker->Release();
1376                 pMoniker = NULL;
1377
1378                 deviceCounter++;
1379             }
1380
1381             pDevEnum->Release();
1382             pDevEnum = NULL;
1383
1384             pEnum->Release();
1385             pEnum = NULL;
1386         }
1387
1388          if(!silent)printf("SETUP: %i Device(s) found\n\n", deviceCounter);
1389     }
1390
1391     comUnInit();
1392
1393     return deviceCounter;
1394 }
1395
1396
1397 // ----------------------------------------------------------------------
1398 //
1399 //
1400 // ----------------------------------------------------------------------
1401
1402 int videoInput::getWidth(int id){
1403
1404     if(isDeviceSetup(id))
1405     {
1406         return VDList[id] ->width;
1407     }
1408
1409     return 0;
1410
1411 }
1412
1413
1414 // ----------------------------------------------------------------------
1415 //
1416 //
1417 // ----------------------------------------------------------------------
1418
1419 int videoInput::getHeight(int id){
1420
1421     if(isDeviceSetup(id))
1422     {
1423         return VDList[id] ->height;
1424     }
1425
1426     return 0;
1427
1428 }
1429
1430 // ----------------------------------------------------------------------
1431 //
1432 //
1433 // ----------------------------------------------------------------------
1434 int videoInput::getFourcc(int id){
1435
1436     if(isDeviceSetup(id))
1437     {
1438         return getFourccFromMediaSubtype(VDList[id]->videoType);
1439     }
1440
1441     return 0;
1442
1443 }
1444
1445 double videoInput::getFPS(int id){
1446
1447     if(isDeviceSetup(id))
1448     {
1449         double frameTime= VDList[id]->requestedFrameTime;
1450         if (frameTime>0) {
1451             return (10000000.0 / frameTime);
1452         }
1453     }
1454
1455     return 0;
1456
1457 }
1458
1459
1460 // ----------------------------------------------------------------------
1461 //
1462 //
1463 // ----------------------------------------------------------------------
1464
1465 int videoInput::getSize(int id){
1466
1467     if(isDeviceSetup(id))
1468     {
1469         return VDList[id] ->videoSize;
1470     }
1471
1472     return 0;
1473
1474 }
1475
1476
1477 // ----------------------------------------------------------------------
1478 // Uses a supplied buffer
1479 // ----------------------------------------------------------------------
1480
1481 bool videoInput::getPixels(int id, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage){
1482
1483     bool success = false;
1484
1485     if(isDeviceSetup(id)){
1486         if(bCallback){
1487             //callback capture
1488
1489             DWORD result = WaitForSingleObject(VDList[id]->sgCallback->hEvent, 1000);
1490             if( result != WAIT_OBJECT_0) return false;
1491
1492             //double paranoia - mutexing with both event and critical section
1493             EnterCriticalSection(&VDList[id]->sgCallback->critSection);
1494
1495                 unsigned char * src = VDList[id]->sgCallback->pixels;
1496                 unsigned char * dst = dstBuffer;
1497                 int height             = VDList[id]->height;
1498                 int width              = VDList[id]->width;
1499
1500                 processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
1501                 VDList[id]->sgCallback->newFrame = false;
1502
1503             LeaveCriticalSection(&VDList[id]->sgCallback->critSection);
1504
1505             ResetEvent(VDList[id]->sgCallback->hEvent);
1506
1507             success = true;
1508
1509         }
1510         else{
1511             //regular capture method
1512             long bufferSize = VDList[id]->videoSize;
1513             HRESULT hr = VDList[id]->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VDList[id]->pBuffer);
1514             if(hr==S_OK){
1515                 int numBytes = VDList[id]->videoSize;
1516                 if (numBytes == bufferSize){
1517
1518                     unsigned char * src = (unsigned char * )VDList[id]->pBuffer;
1519                     unsigned char * dst = dstBuffer;
1520                     int height             = VDList[id]->height;
1521                     int width             = VDList[id]->width;
1522
1523                     processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
1524                     success = true;
1525                 }else{
1526                     if(verbose)printf("ERROR: GetPixels() - bufferSizes do not match!\n");
1527                 }
1528             }else{
1529                 if(verbose)printf("ERROR: GetPixels() - Unable to grab frame for device %i\n", id);
1530             }
1531         }
1532     }
1533
1534     return success;
1535 }
1536
1537
1538 // ----------------------------------------------------------------------
1539 // Returns a buffer
1540 // ----------------------------------------------------------------------
1541 unsigned char * videoInput::getPixels(int id, bool flipRedAndBlue, bool flipImage){
1542
1543     if(isDeviceSetup(id)){
1544            getPixels(id, VDList[id]->pixels, flipRedAndBlue, flipImage);
1545     }
1546
1547     return VDList[id]->pixels;
1548 }
1549
1550
1551
1552 // ----------------------------------------------------------------------
1553 //
1554 //
1555 // ----------------------------------------------------------------------
1556 bool videoInput::isFrameNew(int id){
1557     if(!isDeviceSetup(id)) return false;
1558     if(!bCallback)return true;
1559
1560     bool result = false;
1561     bool freeze = false;
1562
1563     //again super paranoia!
1564     EnterCriticalSection(&VDList[id]->sgCallback->critSection);
1565         result = VDList[id]->sgCallback->newFrame;
1566
1567         //we need to give it some time at the begining to start up so lets check after 400 frames
1568         if(VDList[id]->nFramesRunning > 400 && VDList[id]->sgCallback->freezeCheck > VDList[id]->nFramesForReconnect ){
1569             freeze = true;
1570         }
1571
1572         //we increment the freezeCheck var here - the callback resets it to 1
1573         //so as long as the callback is running this var should never get too high.
1574         //if the callback is not running then this number will get high and trigger the freeze action below
1575         VDList[id]->sgCallback->freezeCheck++;
1576     LeaveCriticalSection(&VDList[id]->sgCallback->critSection);
1577
1578     VDList[id]->nFramesRunning++;
1579
1580     if(freeze && VDList[id]->autoReconnect){
1581         if(verbose)printf("ERROR: Device seems frozen - attempting to reconnect\n");
1582         if( !restartDevice(VDList[id]->myID) ){
1583             if(verbose)printf("ERROR: Unable to reconnect to device\n");
1584         }else{
1585             if(verbose)printf("SUCCESS: Able to reconnect to device\n");
1586         }
1587     }
1588
1589     return result;
1590 }
1591
1592
1593 // ----------------------------------------------------------------------
1594 //
1595 //
1596 // ----------------------------------------------------------------------
1597
1598 bool videoInput::isDeviceSetup(int id){
1599
1600     if(id<devicesFound && VDList[id]->readyToCapture)return true;
1601     else return false;
1602
1603 }
1604
1605
1606 // ----------------------------------------------------------------------
1607 // Gives us a little pop up window to adjust settings
1608 // We do this in a seperate thread now!
1609 // ----------------------------------------------------------------------
1610
1611
1612 void __cdecl videoInput::basicThread(void * objPtr){
1613
1614     //get a reference to the video device
1615     //not a copy as we need to free the filter
1616     videoDevice * vd = *( (videoDevice **)(objPtr) );
1617     ShowFilterPropertyPages(vd->pVideoInputFilter);
1618
1619
1620
1621     //now we free the filter and make sure it set to NULL
1622     if(vd->pVideoInputFilter)vd->pVideoInputFilter->Release();
1623     if(vd->pVideoInputFilter)vd->pVideoInputFilter = NULL;
1624
1625     return;
1626 }
1627
1628 void videoInput::showSettingsWindow(int id){
1629
1630     if(isDeviceSetup(id)){
1631         //HANDLE myTempThread;
1632
1633         //we reconnect to the device as we have freed our reference to it
1634         //why have we freed our reference? because there seemed to be an issue
1635         //with some mpeg devices if we didn't
1636         HRESULT hr = getDevice(&VDList[id]->pVideoInputFilter, id, VDList[id]->wDeviceName, VDList[id]->nDeviceName);
1637         if(hr == S_OK){
1638             //myTempThread = (HANDLE)
1639                 _beginthread(basicThread, 0, (void *)&VDList[id]);
1640         }
1641     }
1642 }
1643
1644
1645 // Set a video signal setting using IAMVideoProcAmp
1646 bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue){
1647     if( !isDeviceSetup(deviceID) )return false;
1648
1649     HRESULT hr;
1650     //bool isSuccessful = false;
1651
1652     videoDevice * VD = VDList[deviceID];
1653
1654     hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1655     if (FAILED(hr)){
1656         printf("setVideoSetting - getDevice Error\n");
1657         return false;
1658     }
1659
1660     IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1661
1662     hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1663     if(FAILED(hr)){
1664         printf("setVideoSetting - QueryInterface Error\n");
1665         if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1666         if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1667         return false;
1668     }
1669
1670     char propStr[16];
1671     getVideoPropertyAsString(Property,propStr);
1672
1673     if (verbose) printf("Setting video setting %s.\n", propStr);
1674
1675     pAMVideoProcAmp->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1676     if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags);
1677     pAMVideoProcAmp->Get(Property, &currentValue, &flags);
1678
1679     if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1680     if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1681     if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1682
1683     return true;
1684
1685 }
1686
1687
1688 // Set a video signal setting using IAMVideoProcAmp
1689 bool videoInput::setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags){
1690     if( !isDeviceSetup(deviceID) )return false;
1691
1692     long min, max, currentValue, flags, defaultValue, stepAmnt;
1693
1694     if( !getVideoSettingFilter(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1695
1696     if(pctValue > 1.0)pctValue = 1.0;
1697     else if(pctValue < 0)pctValue = 0.0;
1698
1699     float range = (float)max - (float)min;
1700     if(range <= 0)return false;
1701     if(stepAmnt == 0) return false;
1702
1703     long value     = (long)( (float)min + range * pctValue );
1704     long rasterValue = value;
1705
1706     //if the range is the stepAmnt then it is just a switch
1707     //so we either set the value to low or high
1708     if( range == stepAmnt ){
1709         if( pctValue < 0.5)rasterValue = min;
1710         else rasterValue = max;
1711     }else{
1712         //we need to rasterize the value to the stepping amnt
1713         long mod         = value % stepAmnt;
1714         float halfStep     = (float)stepAmnt * 0.5f;
1715         if( mod < halfStep ) rasterValue -= mod;
1716         else rasterValue += stepAmnt - mod;
1717         printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue);
1718     }
1719
1720     return setVideoSettingFilter(deviceID, Property, rasterValue, Flags, false);
1721 }
1722
1723
1724 // Set a video signal setting using IAMVideoProcAmp
1725 bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1726     if( !isDeviceSetup(deviceID) )return false;
1727
1728     HRESULT hr;
1729     //bool isSuccessful = false;
1730
1731     char propStr[16];
1732     getVideoPropertyAsString(Property,propStr);
1733
1734     videoDevice * VD = VDList[deviceID];
1735
1736     hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1737     if (FAILED(hr)){
1738         printf("setVideoSetting - getDevice Error\n");
1739         return false;
1740     }
1741
1742     IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1743
1744     hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1745     if(FAILED(hr)){
1746         printf("setVideoSetting - QueryInterface Error\n");
1747         if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1748         if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1749         return false;
1750     }
1751
1752     if (verbose) printf("Setting video setting %s.\n", propStr);
1753     long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags = 0;
1754
1755
1756     pAMVideoProcAmp->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1757     if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1758     pAMVideoProcAmp->Get(Property, &CurrVal, &CapsFlags);
1759
1760     if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1761
1762     if (useDefaultValue) {
1763         pAMVideoProcAmp->Set(Property, Default, VideoProcAmp_Flags_Auto);
1764     }
1765     else{
1766         // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1767         pAMVideoProcAmp->Set(Property, lValue, Flags);
1768     }
1769
1770     if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1771     if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1772     if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1773
1774     return true;
1775
1776 }
1777
1778
1779 bool videoInput::setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags){
1780     if( !isDeviceSetup(deviceID) )return false;
1781
1782     long min, max, currentValue, flags, defaultValue, stepAmnt;
1783
1784     if( !getVideoSettingCamera(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1785
1786     if(pctValue > 1.0)pctValue = 1.0;
1787     else if(pctValue < 0)pctValue = 0.0;
1788
1789     float range = (float)max - (float)min;
1790     if(range <= 0)return false;
1791     if(stepAmnt == 0) return false;
1792
1793     long value     = (long)( (float)min + range * pctValue );
1794     long rasterValue = value;
1795
1796     //if the range is the stepAmnt then it is just a switch
1797     //so we either set the value to low or high
1798     if( range == stepAmnt ){
1799         if( pctValue < 0.5)rasterValue = min;
1800         else rasterValue = max;
1801     }else{
1802         //we need to rasterize the value to the stepping amnt
1803         long mod         = value % stepAmnt;
1804         float halfStep     = (float)stepAmnt * 0.5f;
1805         if( mod < halfStep ) rasterValue -= mod;
1806         else rasterValue += stepAmnt - mod;
1807         printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue);
1808     }
1809
1810     return setVideoSettingCamera(deviceID, Property, rasterValue, Flags, false);
1811 }
1812
1813
1814 bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1815     IAMCameraControl *pIAMCameraControl;
1816     if(isDeviceSetup(deviceID))
1817     {
1818         HRESULT hr;
1819         hr = getDevice(&VDList[deviceID]->pVideoInputFilter, deviceID, VDList[deviceID]->wDeviceName, VDList[deviceID]->nDeviceName);
1820
1821         char propStr[16];
1822         getCameraPropertyAsString(Property,propStr);
1823
1824         if (verbose) printf("Setting video setting %s.\n", propStr);
1825         hr = VDList[deviceID]->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1826         if (FAILED(hr)) {
1827             printf("Error\n");
1828             return false;
1829         }
1830         else
1831         {
1832             long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags;
1833             pIAMCameraControl->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1834             if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1835             pIAMCameraControl->Get(Property, &CurrVal, &CapsFlags);
1836             if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1837             if (useDefaultValue) {
1838                 pIAMCameraControl->Set(Property, Default, CameraControl_Flags_Auto);
1839             }
1840             else
1841             {
1842                 // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1843                 pIAMCameraControl->Set(Property, lValue, Flags);
1844             }
1845             pIAMCameraControl->Release();
1846             return true;
1847         }
1848     }
1849     return false;
1850 }
1851
1852
1853
1854 bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue){
1855     if( !isDeviceSetup(deviceID) )return false;
1856
1857     HRESULT hr;
1858     //bool isSuccessful = false;
1859
1860     videoDevice * VD = VDList[deviceID];
1861
1862     hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1863     if (FAILED(hr)){
1864         printf("setVideoSetting - getDevice Error\n");
1865         return false;
1866     }
1867
1868     IAMCameraControl *pIAMCameraControl = NULL;
1869
1870     hr = VD->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1871     if(FAILED(hr)){
1872         printf("setVideoSetting - QueryInterface Error\n");
1873         if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1874         if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1875         return false;
1876     }
1877
1878     char propStr[16];
1879     getCameraPropertyAsString(Property,propStr);
1880     if (verbose) printf("Setting video setting %s.\n", propStr);
1881
1882     pIAMCameraControl->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1883     if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags);
1884     pIAMCameraControl->Get(Property, &currentValue, &flags);
1885
1886     if(pIAMCameraControl)pIAMCameraControl->Release();
1887     if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1888     if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1889
1890     return true;
1891
1892 }
1893
1894
1895 // ----------------------------------------------------------------------
1896 // Shutsdown the device, deletes the object and creates a new object
1897 // so it is ready to be setup again
1898 // ----------------------------------------------------------------------
1899
1900 void videoInput::stopDevice(int id){
1901     if(id < VI_MAX_CAMERAS)
1902     {
1903         delete VDList[id];
1904         VDList[id] = new videoDevice();
1905     }
1906
1907 }
1908
1909 // ----------------------------------------------------------------------
1910 // Restarts the device with the same settings it was using
1911 //
1912 // ----------------------------------------------------------------------
1913
1914 bool videoInput::restartDevice(int id){
1915     if(isDeviceSetup(id))
1916     {
1917         int conn         = VDList[id]->storeConn;
1918         int tmpW           = VDList[id]->width;
1919         int tmpH           = VDList[id]->height;
1920
1921         bool bFormat    = VDList[id]->specificFormat;
1922         long format     = VDList[id]->formatType;
1923
1924         int nReconnect    = VDList[id]->nFramesForReconnect;
1925         bool bReconnect = VDList[id]->autoReconnect;
1926
1927         unsigned long avgFrameTime = VDList[id]->requestedFrameTime;
1928
1929         stopDevice(id);
1930
1931         //set our fps if needed
1932         if( avgFrameTime != (unsigned long)-1){
1933             VDList[id]->requestedFrameTime = avgFrameTime;
1934         }
1935
1936         if( setupDevice(id, tmpW, tmpH, conn) ){
1937             //reapply the format - ntsc / pal etc
1938             if( bFormat ){
1939                 setFormat(id, format);
1940             }
1941             if( bReconnect ){
1942                 setAutoReconnectOnFreeze(id, true, nReconnect);
1943             }
1944             return true;
1945         }
1946     }
1947     return false;
1948 }
1949
1950 // ----------------------------------------------------------------------
1951 // Shuts down all devices, deletes objects and unitializes com if needed
1952 //
1953 // ----------------------------------------------------------------------
1954 videoInput::~videoInput(){
1955
1956     for(int i = 0; i < VI_MAX_CAMERAS; i++)
1957     {
1958         delete VDList[i];
1959     }
1960     //Unitialize com
1961     comUnInit();
1962 }
1963
1964
1965 //////////////////////////////  VIDEO INPUT  ////////////////////////////////
1966 ////////////////////////////  PRIVATE METHODS  //////////////////////////////
1967
1968 // ----------------------------------------------------------------------
1969 // We only should init com if it hasn't been done so by our apps thread
1970 // Use a static counter to keep track of other times it has been inited
1971 // (do we need to worry about multithreaded apps?)
1972 // ----------------------------------------------------------------------
1973
1974 bool videoInput::comInit(){
1975     /*HRESULT hr = NOERROR;
1976
1977     //no need for us to start com more than once
1978     if(comInitCount == 0 ){
1979
1980         // Initialize the COM library.
1981         //CoInitializeEx so videoInput can run in another thread
1982     #ifdef VI_COM_MULTI_THREADED
1983         hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
1984     #else
1985         hr = CoInitialize(NULL);
1986     #endif
1987         //this is the only case where there might be a problem
1988         //if another library has started com as single threaded
1989         //and we need it multi-threaded - send warning but don't fail
1990         if( hr == RPC_E_CHANGED_MODE){
1991              if(verbose)printf("SETUP - COM already setup - threaded VI might not be possible\n");
1992         }
1993     }
1994
1995     comInitCount++;*/
1996     return true;
1997 }
1998
1999
2000 // ----------------------------------------------------------------------
2001 // Same as above but to unitialize com, decreases counter and frees com
2002 // if no one else is using it
2003 // ----------------------------------------------------------------------
2004
2005 bool videoInput::comUnInit(){
2006     /*if(comInitCount > 0)comInitCount--;        //decrease the count of instances using com
2007
2008        if(comInitCount == 0){
2009            CoUninitialize();    //if there are no instances left - uninitialize com
2010         return true;
2011     }
2012
2013     return false;*/
2014     return true;
2015 }
2016
2017
2018 // ----------------------------------------------------------------------
2019 // This is the size we ask for - we might not get it though :)
2020 //
2021 // ----------------------------------------------------------------------
2022
2023 void videoInput::setAttemptCaptureSize(int id, int w, int h,GUID mediaType){
2024
2025     VDList[id]->tryWidth    = w;
2026     VDList[id]->tryHeight   = h;
2027     VDList[id]->tryDiffSize = true;
2028     VDList[id]->tryVideoType = mediaType;
2029
2030 }
2031
2032 // ----------------------------------------------------------------------
2033 // Set the connection type
2034 // (maybe move to private?)
2035 // ----------------------------------------------------------------------
2036
2037 void videoInput::setPhyCon(int id, int conn){
2038
2039     switch(conn){
2040
2041         case 0:
2042             VDList[id]->connection = PhysConn_Video_Composite;
2043             break;
2044         case 1:
2045             VDList[id]->connection = PhysConn_Video_SVideo;
2046             break;
2047         case 2:
2048             VDList[id]->connection = PhysConn_Video_Tuner;
2049             break;
2050         case 3:
2051             VDList[id]->connection = PhysConn_Video_USB;
2052             break;
2053         case 4:
2054             VDList[id]->connection = PhysConn_Video_1394;
2055             break;
2056         default:
2057             return; //if it is not these types don't set crossbar
2058         break;
2059     }
2060
2061     VDList[id]->storeConn    = conn;
2062     VDList[id]->useCrossbar    = true;
2063 }
2064
2065
2066 // ----------------------------------------------------------------------
2067 // Check that we are not trying to setup a non-existant device
2068 // Then start the graph building!
2069 // ----------------------------------------------------------------------
2070
2071 bool videoInput::setup(int deviceNumber){
2072     devicesFound = getDeviceCount();
2073
2074      if(deviceNumber>devicesFound-1)
2075     {
2076         if(verbose)printf("SETUP: device[%i] not found - you have %i devices available\n", deviceNumber, devicesFound);
2077         if(devicesFound>=0) if(verbose)printf("SETUP: this means that the last device you can use is device[%i] \n",  devicesFound-1);
2078         return false;
2079     }
2080
2081     if(VDList[deviceNumber]->readyToCapture)
2082     {
2083         if(verbose)printf("SETUP: can't setup, device %i is currently being used\n",VDList[deviceNumber]->myID);
2084         return false;
2085     }
2086
2087     HRESULT hr = start(deviceNumber, VDList[deviceNumber]);
2088     if(hr == S_OK)return true;
2089     else return false;
2090 }
2091
2092
2093 // ----------------------------------------------------------------------
2094 // Does both vertical buffer flipping and bgr to rgb swapping
2095 // You have any combination of those.
2096 // ----------------------------------------------------------------------
2097
2098 void videoInput::processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){
2099
2100     int widthInBytes = width * 3;
2101     int numBytes = widthInBytes * height;
2102
2103     if(!bRGB){
2104
2105         //int x = 0;
2106         //int y = 0;
2107
2108         if(bFlip){
2109             for(int y = 0; y < height; y++){
2110                 memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes);
2111             }
2112
2113         }else{
2114             memcpy(dst, src, numBytes);
2115         }
2116     }else{
2117         if(bFlip){
2118
2119             int x = 0;
2120             int y = (height - 1) * widthInBytes;
2121             src += y;
2122
2123             for(int i = 0; i < numBytes; i+=3){
2124                 if(x >= width){
2125                     x = 0;
2126                     src -= widthInBytes*2;
2127                 }
2128
2129                 *dst = *(src+2);
2130                 dst++;
2131
2132                 *dst = *(src+1);
2133                 dst++;
2134
2135                 *dst = *src;
2136                 dst++;
2137
2138                 src+=3;
2139                 x++;
2140             }
2141         }
2142         else{
2143             for(int i = 0; i < numBytes; i+=3){
2144                 *dst = *(src+2);
2145                 dst++;
2146
2147                 *dst = *(src+1);
2148                 dst++;
2149
2150                 *dst = *src;
2151                 dst++;
2152
2153                 src+=3;
2154             }
2155         }
2156     }
2157 }
2158
2159
2160 //------------------------------------------------------------------------------------------
2161 void videoInput::getMediaSubtypeAsString(GUID type, char * typeAsString){
2162
2163     char tmpStr[8];
2164     if( type == MEDIASUBTYPE_RGB24)     sprintf(tmpStr, "RGB24");
2165     else if(type == MEDIASUBTYPE_RGB32) sprintf(tmpStr, "RGB32");
2166     else if(type == MEDIASUBTYPE_RGB555)sprintf(tmpStr, "RGB555");
2167     else if(type == MEDIASUBTYPE_RGB565)sprintf(tmpStr, "RGB565");
2168     else if(type == MEDIASUBTYPE_YUY2)  sprintf(tmpStr, "YUY2");
2169     else if(type == MEDIASUBTYPE_YVYU)  sprintf(tmpStr, "YVYU");
2170     else if(type == MEDIASUBTYPE_YUYV)  sprintf(tmpStr, "YUYV");
2171     else if(type == MEDIASUBTYPE_IYUV)  sprintf(tmpStr, "IYUV");
2172     else if(type == MEDIASUBTYPE_UYVY)  sprintf(tmpStr, "UYVY");
2173     else if(type == MEDIASUBTYPE_YV12)  sprintf(tmpStr, "YV12");
2174     else if(type == MEDIASUBTYPE_YVU9)  sprintf(tmpStr, "YVU9");
2175     else if(type == MEDIASUBTYPE_Y411)  sprintf(tmpStr, "Y411");
2176     else if(type == MEDIASUBTYPE_Y41P)  sprintf(tmpStr, "Y41P");
2177     else if(type == MEDIASUBTYPE_Y211)  sprintf(tmpStr, "Y211");
2178     else if(type == MEDIASUBTYPE_AYUV)  sprintf(tmpStr, "AYUV");
2179     else if(type == MEDIASUBTYPE_MJPG)  sprintf(tmpStr, "MJPG");
2180     else if(type == MEDIASUBTYPE_Y800)  sprintf(tmpStr, "Y800");
2181     else if(type == MEDIASUBTYPE_Y8)    sprintf(tmpStr, "Y8");
2182     else if(type == MEDIASUBTYPE_GREY)  sprintf(tmpStr, "GREY");
2183     else if(type == MEDIASUBTYPE_I420)  sprintf(tmpStr, "I420");
2184     else sprintf(tmpStr, "OTHER");
2185
2186     memcpy(typeAsString, tmpStr, sizeof(char)*8);
2187 }
2188
2189 int videoInput::getFourccFromMediaSubtype(GUID type) {
2190     return type.Data1;
2191 }
2192
2193 GUID *videoInput::getMediaSubtypeFromFourcc(int fourcc){
2194
2195     for (int i=0;i<VI_NUM_TYPES;i++) {
2196         if ( (unsigned long)(unsigned)fourcc == mediaSubtypes[i].Data1 ) {
2197             return &mediaSubtypes[i];
2198         }
2199     }
2200
2201     return NULL;
2202 }
2203
2204
2205 void videoInput::getVideoPropertyAsString(int prop, char * propertyAsString){
2206
2207     char tmpStr[16];
2208
2209     if ( prop==VideoProcAmp_Brightness) sprintf(tmpStr, "Brightness");
2210     else if ( prop==VideoProcAmp_Contrast) sprintf(tmpStr, "Contrast");
2211     else if ( prop==VideoProcAmp_Saturation) sprintf(tmpStr, "Saturation");
2212     else if ( prop==VideoProcAmp_Hue) sprintf(tmpStr, "Hue");
2213     else if ( prop==VideoProcAmp_Gain) sprintf(tmpStr, "Gain");
2214     else if ( prop==VideoProcAmp_Gamma) sprintf(tmpStr, "Gamma");
2215     else if ( prop==VideoProcAmp_ColorEnable) sprintf(tmpStr, "ColorEnable");
2216     else if ( prop==VideoProcAmp_Sharpness) sprintf(tmpStr, "Sharpness");
2217     else sprintf(tmpStr, "%u",prop);
2218
2219     memcpy(propertyAsString, tmpStr, sizeof(char)*16);
2220 }
2221
2222
2223 int videoInput::getVideoPropertyFromCV(int cv_property){
2224
2225     // see VideoProcAmpProperty in strmif.h
2226     switch (cv_property) {
2227         case CV_CAP_PROP_BRIGHTNESS:
2228             return VideoProcAmp_Brightness;
2229
2230         case CV_CAP_PROP_CONTRAST:
2231             return VideoProcAmp_Contrast;
2232
2233         case CV_CAP_PROP_HUE:
2234             return VideoProcAmp_Hue;
2235
2236         case CV_CAP_PROP_SATURATION:
2237             return VideoProcAmp_Saturation;
2238
2239         case CV_CAP_PROP_SHARPNESS:
2240             return VideoProcAmp_Sharpness;
2241
2242         case CV_CAP_PROP_GAMMA:
2243             return VideoProcAmp_Gamma;
2244
2245         case CV_CAP_PROP_MONOCROME:
2246             return VideoProcAmp_ColorEnable;
2247
2248         case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
2249             return VideoProcAmp_WhiteBalance;
2250
2251         case  CV_CAP_PROP_BACKLIGHT:
2252             return VideoProcAmp_BacklightCompensation;
2253
2254         case CV_CAP_PROP_GAIN:
2255             return VideoProcAmp_Gain;
2256     }
2257     return -1;
2258 }
2259
2260 int videoInput::getCameraPropertyFromCV(int cv_property){
2261
2262     // see CameraControlProperty in strmif.h
2263     switch (cv_property) {
2264         case CV_CAP_PROP_PAN:
2265             return CameraControl_Pan;
2266
2267         case CV_CAP_PROP_TILT:
2268             return CameraControl_Tilt;
2269
2270         case CV_CAP_PROP_ROLL:
2271             return CameraControl_Roll;
2272
2273         case CV_CAP_PROP_ZOOM:
2274             return CameraControl_Zoom;
2275
2276         case CV_CAP_PROP_EXPOSURE:
2277             return CameraControl_Exposure;
2278
2279         case CV_CAP_PROP_IRIS:
2280             return CameraControl_Iris;
2281
2282         case CV_CAP_PROP_FOCUS:
2283             return CameraControl_Focus;
2284     }
2285     return -1;
2286 }
2287
2288 void videoInput::getCameraPropertyAsString(int prop, char * propertyAsString){
2289
2290     char tmpStr[16];
2291
2292     if ( prop==CameraControl_Pan) sprintf(tmpStr, "Pan");
2293     else if ( prop==CameraControl_Tilt) sprintf(tmpStr, "Tilt");
2294     else if ( prop==CameraControl_Roll) sprintf(tmpStr, "Roll");
2295     else if ( prop==CameraControl_Zoom) sprintf(tmpStr, "Zoom");
2296     else if ( prop==CameraControl_Exposure) sprintf(tmpStr, "Exposure");
2297     else if ( prop==CameraControl_Iris) sprintf(tmpStr, "Iris");
2298     else if ( prop==CameraControl_Focus) sprintf(tmpStr, "Focus");
2299     else sprintf(tmpStr, "%u",prop);
2300
2301     memcpy(propertyAsString, tmpStr, sizeof(char)*16);
2302 }
2303
2304
2305 //-------------------------------------------------------------------------------------------
2306 static void findClosestSizeAndSubtype(videoDevice * VD, int widthIn, int heightIn, int &widthOut, int &heightOut, GUID & mediatypeOut){
2307     HRESULT hr;
2308
2309     //find perfect match or closest size
2310     int nearW                = 9999999;
2311     int nearH                = 9999999;
2312     //bool foundClosestMatch     = true;
2313
2314     int iCount = 0;
2315     int iSize = 0;
2316     hr = VD->streamConf->GetNumberOfCapabilities(&iCount, &iSize);
2317
2318     if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
2319     {
2320         //For each format type RGB24 YUV2 etc
2321         for (int iFormat = 0; iFormat < iCount; iFormat++)
2322         {
2323             VIDEO_STREAM_CONFIG_CAPS scc;
2324             AM_MEDIA_TYPE *pmtConfig;
2325             hr =  VD->streamConf->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
2326
2327             if (SUCCEEDED(hr)){
2328
2329                 //his is how many diff sizes are available for the format
2330                 int stepX = scc.OutputGranularityX;
2331                 int stepY = scc.OutputGranularityY;
2332
2333                    int tempW = 999999;
2334                    int tempH = 999999;
2335
2336                    //Don't want to get stuck in a loop
2337                    if(stepX < 1 || stepY < 1) continue;
2338
2339                    //if(verbose)printf("min is %i %i max is %i %i - res is %i %i \n", scc.MinOutputSize.cx, scc.MinOutputSize.cy,  scc.MaxOutputSize.cx,  scc.MaxOutputSize.cy, stepX, stepY);
2340                    //if(verbose)printf("min frame duration is %i  max duration is %i\n", scc.MinFrameInterval, scc.MaxFrameInterval);
2341
2342                    bool exactMatch     = false;
2343                    bool exactMatchX    = false;
2344                 bool exactMatchY    = false;
2345
2346                 for(int x = scc.MinOutputSize.cx; x <= scc.MaxOutputSize.cx; x+= stepX){
2347                     //If we find an exact match
2348                     if( widthIn == x ){
2349                         exactMatchX = true;
2350                         tempW = x;
2351                     }
2352                     //Otherwise lets find the closest match based on width
2353                     else if( abs(widthIn-x) < abs(widthIn-tempW) ){
2354                         tempW = x;
2355                     }
2356                 }
2357
2358                 for(int y = scc.MinOutputSize.cy; y <= scc.MaxOutputSize.cy; y+= stepY){
2359                     //If we find an exact match
2360                     if( heightIn == y){
2361                         exactMatchY = true;
2362                         tempH = y;
2363                     }
2364                     //Otherwise lets find the closest match based on height
2365                     else if( abs(heightIn-y) < abs(heightIn-tempH) ){
2366                         tempH = y;
2367                     }
2368                 }
2369
2370                 //see if we have an exact match!
2371                 if(exactMatchX && exactMatchY){
2372                     //foundClosestMatch = false;
2373                     exactMatch = true;
2374
2375                     widthOut        = widthIn;
2376                     heightOut        = heightIn;
2377                     mediatypeOut    = pmtConfig->subtype;
2378                 }
2379
2380                   //otherwise lets see if this filters closest size is the closest
2381                   //available. the closest size is determined by the sum difference
2382                 //of the widths and heights
2383                   else if( abs(widthIn - tempW) + abs(heightIn - tempH)  < abs(widthIn - nearW) + abs(heightIn - nearH) )
2384                   {
2385                       nearW = tempW;
2386                       nearH = tempH;
2387
2388                     widthOut        = nearW;
2389                     heightOut        = nearH;
2390                     mediatypeOut    = pmtConfig->subtype;
2391                   }
2392
2393                 MyDeleteMediaType(pmtConfig);
2394
2395                 //If we have found an exact match no need to search anymore
2396                 if(exactMatch)break;
2397             }
2398          }
2399     }
2400
2401 }
2402
2403
2404 //---------------------------------------------------------------------------------------------------
2405 static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHeight, GUID mediatype){
2406     VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
2407
2408     //store current size
2409     //int tmpWidth  = HEADER(pVih)->biWidth;
2410     //int tmpHeight = HEADER(pVih)->biHeight;
2411     AM_MEDIA_TYPE * tmpType = NULL;
2412
2413     HRESULT    hr = VD->streamConf->GetFormat(&tmpType);
2414     if(hr != S_OK)return false;
2415
2416     //set new size:
2417     //width and height
2418     HEADER(pVih)->biWidth  = attemptWidth;
2419     HEADER(pVih)->biHeight = attemptHeight;
2420
2421     VD->pAmMediaType->formattype = FORMAT_VideoInfo;
2422     VD->pAmMediaType->majortype  = MEDIATYPE_Video;
2423     VD->pAmMediaType->subtype     = mediatype;
2424
2425     //buffer size
2426     VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight*3;
2427
2428     //set fps if requested
2429     if( VD->requestedFrameTime != -1){
2430         pVih->AvgTimePerFrame = VD->requestedFrameTime;
2431     }
2432
2433     //okay lets try new size
2434     hr = VD->streamConf->SetFormat(VD->pAmMediaType);
2435     if(hr == S_OK){
2436         if( tmpType != NULL )MyDeleteMediaType(tmpType);
2437         return true;
2438     }else{
2439         VD->streamConf->SetFormat(tmpType);
2440         if( tmpType != NULL )MyDeleteMediaType(tmpType);
2441     }
2442
2443     return false;
2444 }
2445
2446 // ----------------------------------------------------------------------
2447 // Where all the work happens!
2448 // Attempts to build a graph for the specified device
2449 // ----------------------------------------------------------------------
2450
2451 int videoInput::start(int deviceID, videoDevice *VD){
2452
2453     HRESULT hr             = NOERROR;
2454     VD->myID             = deviceID;
2455     VD->setupStarted    = true;
2456     CAPTURE_MODE           = PIN_CATEGORY_CAPTURE; //Don't worry - it ends up being preview (which is faster)
2457     callbackSetCount     = 1;  //make sure callback method is not changed after setup called
2458
2459     if(verbose)printf("SETUP: Setting up device %i\n",deviceID);
2460
2461     // CREATE THE GRAPH BUILDER //
2462     // Create the filter graph manager and query for interfaces.
2463     hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&VD->pCaptureGraph);
2464     if (FAILED(hr))    // FAILED is a macro that tests the return value
2465     {
2466         if(verbose)printf("ERROR - Could not create the Filter Graph Manager\n");
2467         return hr;
2468     }
2469
2470     //FITLER GRAPH MANAGER//
2471     // Create the Filter Graph Manager.
2472     hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&VD->pGraph);
2473     if (FAILED(hr))
2474     {
2475         if(verbose)printf("ERROR - Could not add the graph builder!\n");
2476         stopDevice(deviceID);
2477         return hr;
2478     }
2479
2480     //SET THE FILTERGRAPH//
2481     hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph);
2482     if (FAILED(hr))
2483     {
2484         if(verbose)printf("ERROR - Could not set filtergraph\n");
2485         stopDevice(deviceID);
2486         return hr;
2487     }
2488
2489     //MEDIA CONTROL (START/STOPS STREAM)//
2490     // Using QueryInterface on the graph builder,
2491     // Get the Media Control object.
2492     hr = VD->pGraph->QueryInterface(IID_IMediaControl, (void **)&VD->pControl);
2493     if (FAILED(hr))
2494     {
2495         if(verbose)printf("ERROR - Could not create the Media Control object\n");
2496            stopDevice(deviceID);
2497         return hr;
2498     }
2499
2500
2501     //FIND VIDEO DEVICE AND ADD TO GRAPH//
2502     //gets the device specified by the second argument.
2503     hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
2504
2505     if (SUCCEEDED(hr)){
2506         if(verbose)printf("SETUP: %s\n", VD->nDeviceName);
2507         hr = VD->pGraph->AddFilter(VD->pVideoInputFilter, VD->wDeviceName);
2508     }else{
2509         if(verbose)printf("ERROR - Could not find specified video device\n");
2510         stopDevice(deviceID);
2511         return hr;
2512     }
2513
2514     //LOOK FOR PREVIEW PIN IF THERE IS NONE THEN WE USE CAPTURE PIN AND THEN SMART TEE TO PREVIEW
2515     IAMStreamConfig *streamConfTest = NULL;
2516     hr = VD->pCaptureGraph->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&streamConfTest);
2517     if(FAILED(hr)){
2518         if(verbose)printf("SETUP: Couldn't find preview pin using SmartTee\n");
2519     }else{
2520          CAPTURE_MODE = PIN_CATEGORY_PREVIEW;
2521          streamConfTest->Release();
2522          streamConfTest = NULL;
2523     }
2524
2525     //CROSSBAR (SELECT PHYSICAL INPUT TYPE)//
2526     //my own function that checks to see if the device can support a crossbar and if so it routes it.
2527     //webcams tend not to have a crossbar so this function will also detect a webcams and not apply the crossbar
2528     if(VD->useCrossbar)
2529     {
2530         if(verbose)printf("SETUP: Checking crossbar\n");
2531         routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE);
2532     }
2533
2534
2535     //we do this because webcams don't have a preview mode
2536     hr = VD->pCaptureGraph->FindInterface(&CAPTURE_MODE, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&VD->streamConf);
2537     if(FAILED(hr)){
2538         if(verbose)printf("ERROR: Couldn't config the stream!\n");
2539         stopDevice(deviceID);
2540         return hr;
2541     }
2542
2543     //NOW LETS DEAL WITH GETTING THE RIGHT SIZE
2544     hr = VD->streamConf->GetFormat(&VD->pAmMediaType);
2545     if(FAILED(hr)){
2546         if(verbose)printf("ERROR: Couldn't getFormat for pAmMediaType!\n");
2547         stopDevice(deviceID);
2548         return hr;
2549     }
2550
2551     VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
2552     int currentWidth    =  HEADER(pVih)->biWidth;
2553     int currentHeight    =  HEADER(pVih)->biHeight;
2554
2555     bool customSize = VD->tryDiffSize;
2556
2557     bool foundSize  = false;
2558
2559     if(customSize){
2560         if(verbose)    printf("SETUP: Default Format is set to %i by %i \n", currentWidth, currentHeight);
2561
2562         char guidStr[8];
2563             // try specified format and size
2564             getMediaSubtypeAsString(VD->tryVideoType, guidStr);
2565             if(verbose)printf("SETUP: trying specified format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight);
2566
2567             if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, VD->tryVideoType) ){
2568                 VD->setSize(VD->tryWidth, VD->tryHeight);
2569                 foundSize = true;
2570             } else {
2571                 // try specified size with all formats
2572                 for(int i = 0; i < VI_NUM_TYPES; i++){
2573
2574                     getMediaSubtypeAsString(mediaSubtypes[i], guidStr);
2575
2576                     if(verbose)printf("SETUP: trying format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight);
2577                     if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){
2578                         VD->setSize(VD->tryWidth, VD->tryHeight);
2579                         foundSize = true;
2580                         break;
2581                     }
2582                 }
2583             }
2584
2585
2586         //if we didn't find the requested size - lets try and find the closest matching size
2587         if( foundSize == false ){
2588             if( verbose )printf("SETUP: couldn't find requested size - searching for closest matching size\n");
2589
2590             int closestWidth        = -1;
2591             int closestHeight        = -1;
2592             GUID newMediaSubtype;
2593
2594             findClosestSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, closestWidth, closestHeight, newMediaSubtype);
2595
2596             if( closestWidth != -1 && closestHeight != -1){
2597                 getMediaSubtypeAsString(newMediaSubtype, guidStr);
2598
2599                 if(verbose)printf("SETUP: closest supported size is %s @ %i %i\n", guidStr, closestWidth, closestHeight);
2600                 if( setSizeAndSubtype(VD, closestWidth, closestHeight, newMediaSubtype) ){
2601                     VD->setSize(closestWidth, closestHeight);
2602                     foundSize = true;
2603                 }
2604             }
2605         }
2606     }
2607
2608     //if we didn't specify a custom size or if we did but couldn't find it lets setup with the default settings
2609     if(customSize == false || foundSize == false){
2610         if( VD->requestedFrameTime != -1 ){
2611             pVih->AvgTimePerFrame  = VD->requestedFrameTime;
2612             hr = VD->streamConf->SetFormat(VD->pAmMediaType);
2613         }
2614         VD->setSize(currentWidth, currentHeight);
2615     }
2616
2617     //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
2618     // Create the Sample Grabber.
2619     hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&VD->pGrabberF);
2620     if (FAILED(hr)){
2621         if(verbose)printf("Could not Create Sample Grabber - CoCreateInstance()\n");
2622         stopDevice(deviceID);
2623         return hr;
2624     }
2625
2626     hr = VD->pGraph->AddFilter(VD->pGrabberF, L"Sample Grabber");
2627     if (FAILED(hr)){
2628         if(verbose)printf("Could not add Sample Grabber - AddFilter()\n");
2629         stopDevice(deviceID);
2630         return hr;
2631     }
2632
2633     hr = VD->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&VD->pGrabber);
2634     if (FAILED(hr)){
2635         if(verbose)printf("ERROR: Could not query SampleGrabber\n");
2636         stopDevice(deviceID);
2637         return hr;
2638     }
2639
2640
2641     //Set Params - One Shot should be false unless you want to capture just one buffer
2642     hr = VD->pGrabber->SetOneShot(FALSE);
2643     if(bCallback){
2644         hr = VD->pGrabber->SetBufferSamples(FALSE);
2645     }else{
2646         hr = VD->pGrabber->SetBufferSamples(TRUE);
2647     }
2648
2649     if(bCallback){
2650         //Tell the grabber to use our callback function - 0 is for SampleCB and 1 for BufferCB
2651         //We use SampleCB
2652         hr = VD->pGrabber->SetCallback(VD->sgCallback, 0);
2653         if (FAILED(hr)){
2654             if(verbose)printf("ERROR: problem setting callback\n");
2655             stopDevice(deviceID);
2656             return hr;
2657         }else{
2658             if(verbose)printf("SETUP: Capture callback set\n");
2659         }
2660     }
2661
2662     //MEDIA CONVERSION
2663     //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image)
2664     //zero the media type - lets try this :) - maybe this works?
2665     AM_MEDIA_TYPE mt;
2666     ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
2667
2668     mt.majortype     = MEDIATYPE_Video;
2669     mt.subtype         = MEDIASUBTYPE_RGB24;
2670     mt.formattype     = FORMAT_VideoInfo;
2671
2672     //VD->pAmMediaType->subtype = VD->videoType;
2673     hr = VD->pGrabber->SetMediaType(&mt);
2674
2675     //lets try freeing our stream conf here too
2676     //this will fail if the device is already running
2677     if(VD->streamConf){
2678         VD->streamConf->Release();
2679         VD->streamConf = NULL;
2680     }else{
2681         if(verbose)printf("ERROR: connecting device - prehaps it is already being used?\n");
2682         stopDevice(deviceID);
2683         return S_FALSE;
2684     }
2685
2686
2687     //NULL RENDERER//
2688     //used to give the video stream somewhere to go to.
2689     hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&VD->pDestFilter));
2690     if (FAILED(hr)){
2691         if(verbose)printf("ERROR: Could not create filter - NullRenderer\n");
2692         stopDevice(deviceID);
2693         return hr;
2694     }
2695
2696     hr = VD->pGraph->AddFilter(VD->pDestFilter, L"NullRenderer");
2697     if (FAILED(hr)){
2698         if(verbose)printf("ERROR: Could not add filter - NullRenderer\n");
2699         stopDevice(deviceID);
2700         return hr;
2701     }
2702
2703     //RENDER STREAM//
2704     //This is where the stream gets put together.
2705     hr = VD->pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, VD->pGrabberF, VD->pDestFilter);
2706
2707     if (FAILED(hr)){
2708         if(verbose)printf("ERROR: Could not connect pins - RenderStream()\n");
2709         stopDevice(deviceID);
2710         return hr;
2711     }
2712
2713
2714     //EXP - lets try setting the sync source to null - and make it run as fast as possible
2715     {
2716         IMediaFilter *pMediaFilter = 0;
2717         hr = VD->pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
2718         if (FAILED(hr)){
2719             if(verbose)printf("ERROR: Could not get IID_IMediaFilter interface\n");
2720         }else{
2721             pMediaFilter->SetSyncSource(NULL);
2722             pMediaFilter->Release();
2723         }
2724     }
2725
2726
2727     //LETS RUN THE STREAM!
2728     hr = VD->pControl->Run();
2729
2730     if (FAILED(hr)){
2731          if(verbose)printf("ERROR: Could not start graph\n");
2732          stopDevice(deviceID);
2733          return hr;
2734     }
2735
2736
2737     //MAKE SURE THE DEVICE IS SENDING VIDEO BEFORE WE FINISH
2738     if(!bCallback){
2739
2740         long bufferSize = VD->videoSize;
2741
2742         while( hr != S_OK){
2743             hr = VD->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VD->pBuffer);
2744             Sleep(10);
2745         }
2746
2747     }
2748
2749     if(verbose)printf("SETUP: Device is setup and ready to capture.\n\n");
2750     VD->readyToCapture = true;
2751
2752     //Release filters - seen someone else do this
2753     //looks like it solved the freezes
2754
2755     //if we release this then we don't have access to the settings
2756     //we release our video input filter but then reconnect with it
2757     //each time we need to use it
2758     VD->pVideoInputFilter->Release();
2759     VD->pVideoInputFilter = NULL;
2760
2761     VD->pGrabberF->Release();
2762     VD->pGrabberF = NULL;
2763
2764     VD->pDestFilter->Release();
2765     VD->pDestFilter = NULL;
2766
2767     return S_OK;
2768 }
2769
2770
2771 // ----------------------------------------------------------------------
2772 // Returns number of good devices
2773 //
2774 // ----------------------------------------------------------------------
2775
2776 int videoInput::getDeviceCount(){
2777
2778
2779     ICreateDevEnum *pDevEnum = NULL;
2780     IEnumMoniker *pEnum = NULL;
2781     int deviceCounter = 0;
2782
2783     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
2784         CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
2785         reinterpret_cast<void**>(&pDevEnum));
2786
2787
2788     if (SUCCEEDED(hr))
2789     {
2790         // Create an enumerator for the video capture category.
2791         hr = pDevEnum->CreateClassEnumerator(
2792             CLSID_VideoInputDeviceCategory,
2793             &pEnum, 0);
2794
2795        if(hr == S_OK){
2796             IMoniker *pMoniker = NULL;
2797             while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
2798
2799                 IPropertyBag *pPropBag;
2800                 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
2801                     (void**)(&pPropBag));
2802
2803                 if (FAILED(hr)){
2804                     pMoniker->Release();
2805                     continue;  // Skip this one, maybe the next one will work.
2806                 }
2807
2808                 pPropBag->Release();
2809                 pPropBag = NULL;
2810
2811                 pMoniker->Release();
2812                 pMoniker = NULL;
2813
2814                 deviceCounter++;
2815             }
2816
2817             pEnum->Release();
2818             pEnum = NULL;
2819         }
2820
2821         pDevEnum->Release();
2822         pDevEnum = NULL;
2823     }
2824     return deviceCounter;
2825 }
2826
2827
2828 // ----------------------------------------------------------------------
2829 // Do we need this?
2830 //
2831 // Enumerate all of the video input devices
2832 // Return the filter with a matching friendly name
2833 // ----------------------------------------------------------------------
2834
2835 HRESULT videoInput::getDevice(IBaseFilter** gottaFilter, int deviceId, WCHAR * wDeviceName, char * nDeviceName){
2836     BOOL done = false;
2837     int deviceCounter = 0;
2838
2839     // Create the System Device Enumerator.
2840     ICreateDevEnum *pSysDevEnum = NULL;
2841     HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
2842     if (FAILED(hr))
2843     {
2844         return hr;
2845     }
2846
2847     // Obtain a class enumerator for the video input category.
2848     IEnumMoniker *pEnumCat = NULL;
2849     hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
2850
2851     if (hr == S_OK)
2852     {
2853         // Enumerate the monikers.
2854         IMoniker *pMoniker = NULL;
2855         ULONG cFetched;
2856         while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done))
2857         {
2858             if(deviceCounter == deviceId)
2859             {
2860                 // Bind the first moniker to an object
2861                 IPropertyBag *pPropBag;
2862                 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
2863                 if (SUCCEEDED(hr))
2864                 {
2865                     // To retrieve the filter's friendly name, do the following:
2866                     VARIANT varName;
2867                     VariantInit(&varName);
2868                     hr = pPropBag->Read(L"FriendlyName", &varName, 0);
2869                     if (SUCCEEDED(hr))
2870                     {
2871
2872                         //copy the name to nDeviceName & wDeviceName
2873                         int count = 0;
2874                         while( varName.bstrVal[count] != 0x00 ) {
2875                                wDeviceName[count] = varName.bstrVal[count];
2876                                nDeviceName[count] = (char)varName.bstrVal[count];
2877                                count++;
2878                          }
2879
2880                         // We found it, so send it back to the caller
2881                         hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter);
2882                         done = true;
2883                     }
2884                     VariantClear(&varName);
2885                     pPropBag->Release();
2886                     pPropBag = NULL;
2887                     pMoniker->Release();
2888                     pMoniker = NULL;
2889                 }
2890             }
2891             deviceCounter++;
2892         }
2893         pEnumCat->Release();
2894         pEnumCat = NULL;
2895     }
2896     pSysDevEnum->Release();
2897     pSysDevEnum = NULL;
2898
2899     if (done) {
2900         return hr;    // found it, return native error
2901     } else {
2902         return VFW_E_NOT_FOUND;    // didn't find it error
2903     }
2904 }
2905
2906
2907 // ----------------------------------------------------------------------
2908 // Show the property pages for a filter
2909 // This is stolen from the DX9 SDK
2910 // ----------------------------------------------------------------------
2911
2912 HRESULT videoInput::ShowFilterPropertyPages(IBaseFilter *pFilter){
2913
2914     ISpecifyPropertyPages *pProp;
2915
2916     HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
2917     if (SUCCEEDED(hr))
2918     {
2919         // Get the filter's name and IUnknown pointer.
2920         FILTER_INFO FilterInfo;
2921         hr = pFilter->QueryFilterInfo(&FilterInfo);
2922         IUnknown *pFilterUnk;
2923         pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);
2924
2925         // Show the page.
2926         CAUUID caGUID;
2927         pProp->GetPages(&caGUID);
2928         pProp->Release();
2929         OleCreatePropertyFrame(
2930             NULL,                   // Parent window
2931             0, 0,                   // Reserved
2932             FilterInfo.achName,     // Caption for the dialog box
2933             1,                      // Number of objects (just the filter)
2934             &pFilterUnk,            // Array of object pointers.
2935             caGUID.cElems,          // Number of property pages
2936             caGUID.pElems,          // Array of property page CLSIDs
2937             0,                      // Locale identifier
2938             0, NULL                 // Reserved
2939         );
2940
2941         // Clean up.
2942         if(pFilterUnk)pFilterUnk->Release();
2943         if(FilterInfo.pGraph)FilterInfo.pGraph->Release();
2944         CoTaskMemFree(caGUID.pElems);
2945     }
2946     return hr;
2947 }
2948
2949 HRESULT videoInput::ShowStreamPropertyPages(IAMStreamConfig  * /*pStream*/){
2950
2951     HRESULT hr             = NOERROR;
2952     return hr;
2953 }
2954
2955 // ----------------------------------------------------------------------
2956 // This code was also brazenly stolen from the DX9 SDK
2957 // Pass it a file name in wszPath, and it will save the filter graph to that file.
2958 // ----------------------------------------------------------------------
2959
2960 HRESULT videoInput::SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) {
2961     const WCHAR wszStreamName[] = L"ActiveMovieGraph";
2962     HRESULT hr;
2963     IStorage *pStorage = NULL;
2964
2965     // First, create a document file which will hold the GRF file
2966     hr = StgCreateDocfile(
2967         wszPath,
2968         STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
2969         0, &pStorage);
2970     if(FAILED(hr))
2971     {
2972         return hr;
2973     }
2974
2975     // Next, create a stream to store.
2976     IStream *pStream;
2977     hr = pStorage->CreateStream(
2978         wszStreamName,
2979         STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
2980         0, 0, &pStream);
2981     if (FAILED(hr))
2982     {
2983         pStorage->Release();
2984         return hr;
2985     }
2986
2987     // The IPersistStream converts a stream into a persistent object.
2988     IPersistStream *pPersist = NULL;
2989     pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast<void**>(&pPersist));
2990     hr = pPersist->Save(pStream, TRUE);
2991     pStream->Release();
2992     pPersist->Release();
2993     if (SUCCEEDED(hr))
2994     {
2995         hr = pStorage->Commit(STGC_DEFAULT);
2996     }
2997     pStorage->Release();
2998     return hr;
2999 }
3000
3001
3002 // ----------------------------------------------------------------------
3003 // For changing the input types
3004 //
3005 // ----------------------------------------------------------------------
3006
3007 HRESULT videoInput::routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode){
3008
3009     //create local ICaptureGraphBuilder2
3010     ICaptureGraphBuilder2 *pBuild = NULL;
3011      pBuild = *ppBuild;
3012
3013      //create local IBaseFilter
3014      IBaseFilter *pVidFilter = NULL;
3015      pVidFilter = * pVidInFilter;
3016
3017     // Search upstream for a crossbar.
3018     IAMCrossbar *pXBar1 = NULL;
3019     HRESULT hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pVidFilter,
3020             IID_IAMCrossbar, (void**)&pXBar1);
3021     if (SUCCEEDED(hr))
3022     {
3023
3024         bool foundDevice = false;
3025
3026         if(verbose)printf("SETUP: You are not a webcam! Setting Crossbar\n");
3027         pXBar1->Release();
3028
3029         IAMCrossbar *Crossbar;
3030         hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Interleaved, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
3031
3032         if(hr != NOERROR){
3033             hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Video, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
3034         }
3035
3036         LONG lInpin, lOutpin;
3037         hr = Crossbar->get_PinCounts(&lOutpin , &lInpin);
3038
3039         BOOL iPin=TRUE; LONG pIndex=0 , pRIndex=0 , pType=0;
3040
3041         while( pIndex < lInpin)
3042         {
3043             hr = Crossbar->get_CrossbarPinInfo( iPin , pIndex , &pRIndex , &pType);
3044
3045             if( pType == conType){
3046                     if(verbose)printf("SETUP: Found Physical Interface");
3047
3048                     switch(conType){
3049
3050                         case PhysConn_Video_Composite:
3051                             if(verbose)printf(" - Composite\n");
3052                             break;
3053                         case PhysConn_Video_SVideo:
3054                             if(verbose)printf(" - S-Video\n");
3055                             break;
3056                         case PhysConn_Video_Tuner:
3057                             if(verbose)printf(" - Tuner\n");
3058                             break;
3059                         case PhysConn_Video_USB:
3060                              if(verbose)printf(" - USB\n");
3061                             break;
3062                         case PhysConn_Video_1394:
3063                             if(verbose)printf(" - Firewire\n");
3064                             break;
3065                     }
3066
3067                 foundDevice = true;
3068                 break;
3069             }
3070             pIndex++;
3071
3072         }
3073
3074         if(foundDevice){
3075             BOOL OPin=FALSE; LONG pOIndex=0 , pORIndex=0 , pOType=0;
3076             while( pOIndex < lOutpin)
3077             {
3078                 hr = Crossbar->get_CrossbarPinInfo( OPin , pOIndex , &pORIndex , &pOType);
3079                 if( pOType == PhysConn_Video_VideoDecoder)
3080                     break;
3081             }
3082             Crossbar->Route(pOIndex,pIndex);
3083         }else{
3084             if(verbose) printf("SETUP: Didn't find specified Physical Connection type. Using Defualt. \n");
3085         }
3086
3087         //we only free the crossbar when we close or restart the device
3088         //we were getting a crash otherwise
3089         //if(Crossbar)Crossbar->Release();
3090         //if(Crossbar)Crossbar = NULL;
3091
3092         if(pXBar1)pXBar1->Release();
3093         if(pXBar1)pXBar1 = NULL;
3094
3095     }else{
3096         if(verbose) printf("SETUP: You are a webcam or snazzy firewire cam! No Crossbar needed\n");
3097         return hr;
3098     }
3099
3100     return hr;
3101 }
3102
3103
3104 /********************* Capturing video from camera via DirectShow *********************/
3105
3106 class CvCaptureCAM_DShow : public CvCapture
3107 {
3108 public:
3109     CvCaptureCAM_DShow();
3110     virtual ~CvCaptureCAM_DShow();
3111
3112     virtual bool open( int index );
3113     virtual void close();
3114     virtual double getProperty(int);
3115     virtual bool setProperty(int, double);
3116     virtual bool grabFrame();
3117     virtual IplImage* retrieveFrame(int);
3118     virtual int getCaptureDomain() { return CV_CAP_DSHOW; } // Return the type of the capture object: CV_CAP_VFW, etc...
3119
3120 protected:
3121     void init();
3122
3123     int index, width, height,fourcc;
3124     int widthSet, heightSet;
3125     IplImage* frame;
3126     static videoInput VI;
3127 };
3128
3129
3130 struct SuppressVideoInputMessages
3131 {
3132     SuppressVideoInputMessages() { videoInput::setVerbose(false); }
3133 };
3134
3135 static SuppressVideoInputMessages do_it;
3136 videoInput CvCaptureCAM_DShow::VI;
3137
3138 CvCaptureCAM_DShow::CvCaptureCAM_DShow()
3139 {
3140     index = -1;
3141     frame = 0;
3142     width = height = fourcc = -1;
3143     widthSet = heightSet = -1;
3144     CoInitialize(0);
3145 }
3146
3147 CvCaptureCAM_DShow::~CvCaptureCAM_DShow()
3148 {
3149     close();
3150     CoUninitialize();
3151 }
3152
3153 void CvCaptureCAM_DShow::close()
3154 {
3155     if( index >= 0 )
3156     {
3157         VI.stopDevice(index);
3158         index = -1;
3159         cvReleaseImage(&frame);
3160     }
3161     widthSet = heightSet = width = height = -1;
3162 }
3163
3164 // Initialize camera input
3165 bool CvCaptureCAM_DShow::open( int _index )
3166 {
3167     int try_index = _index;
3168     int devices = 0;
3169
3170     close();
3171     devices = VI.listDevices(true);
3172     if (devices == 0)
3173         return false;
3174     try_index = try_index < 0 ? 0 : (try_index > devices-1 ? devices-1 : try_index);
3175     VI.setupDevice(try_index);
3176     if( !VI.isDeviceSetup(try_index) )
3177         return false;
3178     index = try_index;
3179     return true;
3180 }
3181
3182 bool CvCaptureCAM_DShow::grabFrame()
3183 {
3184     return true;
3185 }
3186
3187
3188 IplImage* CvCaptureCAM_DShow::retrieveFrame(int)
3189 {
3190     if( !frame || VI.getWidth(index) != frame->width || VI.getHeight(index) != frame->height )
3191     {
3192         if (frame)
3193             cvReleaseImage( &frame );
3194         int w = VI.getWidth(index), h = VI.getHeight(index);
3195         frame = cvCreateImage( cvSize(w,h), 8, 3 );
3196     }
3197
3198     if (VI.getPixels( index, (uchar*)frame->imageData, false, true ))
3199         return frame;
3200     else
3201         return NULL;
3202 }
3203
3204 double CvCaptureCAM_DShow::getProperty( int property_id )
3205 {
3206
3207     long min_value,max_value,stepping_delta,current_value,flags,defaultValue;
3208
3209     // image format proprrties
3210     switch( property_id )
3211     {
3212     case CV_CAP_PROP_FRAME_WIDTH:
3213         return VI.getWidth(index);
3214
3215     case CV_CAP_PROP_FRAME_HEIGHT:
3216         return VI.getHeight(index);
3217
3218     case CV_CAP_PROP_FOURCC:
3219         return VI.getFourcc(index);
3220
3221     case CV_CAP_PROP_FPS:
3222         return VI.getFPS(index);
3223     }
3224
3225     // video filter properties
3226     switch( property_id )
3227     {
3228     case CV_CAP_PROP_BRIGHTNESS:
3229     case CV_CAP_PROP_CONTRAST:
3230     case CV_CAP_PROP_HUE:
3231     case CV_CAP_PROP_SATURATION:
3232     case CV_CAP_PROP_SHARPNESS:
3233     case CV_CAP_PROP_GAMMA:
3234     case CV_CAP_PROP_MONOCROME:
3235     case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
3236     case CV_CAP_PROP_BACKLIGHT:
3237     case CV_CAP_PROP_GAIN:
3238         if (VI.getVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value;
3239     }
3240
3241     // camera properties
3242     switch( property_id )
3243     {
3244     case CV_CAP_PROP_PAN:
3245     case CV_CAP_PROP_TILT:
3246     case CV_CAP_PROP_ROLL:
3247     case CV_CAP_PROP_ZOOM:
3248     case CV_CAP_PROP_EXPOSURE:
3249     case CV_CAP_PROP_IRIS:
3250     case CV_CAP_PROP_FOCUS:
3251         if (VI.getVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value;
3252
3253     }
3254
3255     // unknown parameter or value not available
3256     return -1;
3257 }
3258
3259 bool CvCaptureCAM_DShow::setProperty( int property_id, double value )
3260 {
3261     // image capture properties
3262     bool handled = false;
3263     switch( property_id )
3264     {
3265     case CV_CAP_PROP_FRAME_WIDTH:
3266         width = cvRound(value);
3267         handled = true;
3268         break;
3269
3270     case CV_CAP_PROP_FRAME_HEIGHT:
3271         height = cvRound(value);
3272         handled = true;
3273         break;
3274
3275     case CV_CAP_PROP_FOURCC:
3276         fourcc = (int)(unsigned long)(value);
3277         if ( fourcc == -1 ) {
3278             // following cvCreateVideo usage will pop up caprturepindialog here if fourcc=-1
3279             // TODO - how to create a capture pin dialog
3280         }
3281         handled = true;
3282         break;
3283
3284     case CV_CAP_PROP_FPS:
3285         int fps = cvRound(value);
3286         if (fps != VI.getFPS(index))
3287         {
3288             VI.stopDevice(index);
3289             VI.setIdealFramerate(index,fps);
3290             if (widthSet > 0 && heightSet > 0)
3291                 VI.setupDevice(index, widthSet, heightSet);
3292             else
3293                 VI.setupDevice(index);
3294         }
3295         return VI.isDeviceSetup(index);
3296
3297     }
3298
3299     if ( handled ) {
3300         // a stream setting
3301         if( width > 0 && height > 0 )
3302         {
3303             if( width != VI.getWidth(index) || height != VI.getHeight(index) )//|| fourcc != VI.getFourcc(index) )
3304             {
3305                 int fps = static_cast<int>(VI.getFPS(index));
3306                 VI.stopDevice(index);
3307                 VI.setIdealFramerate(index, fps);
3308                 VI.setupDeviceFourcc(index, width, height, fourcc);
3309             }
3310
3311             bool success = VI.isDeviceSetup(index);
3312             if (success)
3313             {
3314                 widthSet = width;
3315                 heightSet = height;
3316                 width = height = fourcc = -1;
3317             }
3318             return success;
3319         }
3320         return true;
3321     }
3322
3323     // show video/camera filter dialog
3324     if ( property_id == CV_CAP_PROP_SETTINGS ) {
3325         VI.showSettingsWindow(index);
3326         return true;
3327     }
3328
3329     //video Filter properties
3330     switch( property_id )
3331     {
3332     case CV_CAP_PROP_BRIGHTNESS:
3333     case CV_CAP_PROP_CONTRAST:
3334     case CV_CAP_PROP_HUE:
3335     case CV_CAP_PROP_SATURATION:
3336     case CV_CAP_PROP_SHARPNESS:
3337     case CV_CAP_PROP_GAMMA:
3338     case CV_CAP_PROP_MONOCROME:
3339     case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
3340     case CV_CAP_PROP_BACKLIGHT:
3341     case CV_CAP_PROP_GAIN:
3342         return VI.setVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),(long)value);
3343     }
3344
3345     //camera properties
3346     switch( property_id )
3347     {
3348     case CV_CAP_PROP_PAN:
3349     case CV_CAP_PROP_TILT:
3350     case CV_CAP_PROP_ROLL:
3351     case CV_CAP_PROP_ZOOM:
3352     case CV_CAP_PROP_EXPOSURE:
3353     case CV_CAP_PROP_IRIS:
3354     case CV_CAP_PROP_FOCUS:
3355         return VI.setVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),(long)value);
3356     }
3357
3358     return false;
3359 }
3360
3361
3362 CvCapture* cvCreateCameraCapture_DShow( int index )
3363 {
3364     CvCaptureCAM_DShow* capture = new CvCaptureCAM_DShow;
3365
3366     try
3367     {
3368         if( capture->open( index ))
3369             return capture;
3370     }
3371     catch(...)
3372     {
3373         delete capture;
3374         throw;
3375     }
3376
3377     delete capture;
3378     return 0;
3379 }
3380
3381 #endif