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