1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
10 // Intel License Agreement
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
19 // * Redistribution's of source code must retain the above copyright notice,
20 // this list of conditions and the following disclaimer.
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.
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.
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.
42 #include "precomp.hpp"
44 #if (defined WIN32 || defined _WIN32) && defined HAVE_DSHOW
47 DirectShow-based Video Capturing module is based on
48 videoInput library by Theodore Watson:
49 http://muonics.net/school/spring05/videoInput/
51 Below is the original copyright
54 //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59 //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
62 //////////////////////////////////////////////////////////
63 //Written by Theodore Watson - theo.watson@gmail.com //
64 //Do whatever you want with this code but if you find //
65 //a bug or make an improvement I would love to know! //
67 //Warning This code is experimental //
68 //use at your own risk :) //
69 //////////////////////////////////////////////////////////
70 /////////////////////////////////////////////////////////
75 Dillip Kumar Kara for crossbar code.
76 Zachary Lieberman for getting me into this stuff
77 and for being so generous with time and code.
78 The guys at Potion Design for helping me with VC++
79 Josh Fisher for being a serious C++ nerd :)
80 Golan Levin for helping me debug the strangest
81 and slowest bug in the world!
83 And all the people using this library who send in
84 bugs, suggestions and improvements who keep me working on
85 the next version - yeah thanks a lot ;)
88 /////////////////////////////////////////////////////////
90 #include "precomp.hpp"
92 #if defined _MSC_VER && _MSC_VER >= 100
93 //'sprintf': name was marked as #pragma deprecated
94 #pragma warning(disable: 4995)
106 //Include Directshow stuff here so we don't worry about needing all the h files.
107 #if defined _MSC_VER && _MSC_VER >= 1500
110 # include "Aviriff.h"
111 # include "dvdmedia.h"
112 # include "bdaiface.h"
115 # define __extension__
116 typedef BOOL WINBOOL;
119 #include "dshow/dshow.h"
120 #include "dshow/dvdmedia.h"
121 #include "dshow/bdatypes.h"
123 interface IEnumPIDMap : public IUnknown
126 virtual HRESULT STDMETHODCALLTYPE Next(
127 /* [in] */ ULONG cRequest,
128 /* [size_is][out][in] */ PID_MAP *pPIDMap,
129 /* [out] */ ULONG *pcReceived) = 0;
131 virtual HRESULT STDMETHODCALLTYPE Skip(
132 /* [in] */ ULONG cRecords) = 0;
134 virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
136 virtual HRESULT STDMETHODCALLTYPE Clone(
137 /* [out] */ IEnumPIDMap **ppIEnumPIDMap) = 0;
139 virtual ~IEnumPIDMap() {}
142 interface IMPEG2PIDMap : public IUnknown
144 virtual HRESULT STDMETHODCALLTYPE MapPID(
145 /* [in] */ ULONG culPID,
146 /* [in] */ ULONG *pulPID,
147 /* [in] */ MEDIA_SAMPLE_CONTENT MediaSampleContent) = 0;
149 virtual HRESULT STDMETHODCALLTYPE UnmapPID(
150 /* [in] */ ULONG culPID,
151 /* [in] */ ULONG *pulPID) = 0;
153 virtual HRESULT STDMETHODCALLTYPE EnumPIDMap(
154 /* [out] */ IEnumPIDMap **pIEnumPIDMap) = 0;
156 virtual ~IMPEG2PIDMap() {}
164 //this is for TryEnterCriticalSection
166 #define _WIN32_WINNT 0x400
171 MEDIASUBTYPE_I420 : TGUID ='{30323449-0000-0010-8000-00AA00389B71}';
172 MEDIASUBTYPE_Y800 : TGUID ='{30303859-0000-0010-8000-00AA00389B71}';
173 MEDIASUBTYPE_Y8 : TGUID ='{20203859-0000-0010-8000-00AA00389B71}';
174 MEDIASUBTYPE_Y160 : TGUID ='{30363159-0000-0010-8000-00AA00389B71}';
175 MEDIASUBTYPE_YV16 : TGUID ='{32315659-0000-0010-8000-00AA00389B71}';
176 MEDIASUBTYPE_Y422 : TGUID ='{32323459-0000-0010-8000-00AA00389B71}';
177 MEDIASUBTYPE_GREY : TGUID ='{59455247-0000-0010-8000-00AA00389B71}';
180 #include <initguid.h>
182 DEFINE_GUID(MEDIASUBTYPE_GREY, 0x59455247, 0x0000, 0x0010, 0x80, 0x00,
183 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
184 DEFINE_GUID(MEDIASUBTYPE_Y8, 0x20203859, 0x0000, 0x0010, 0x80, 0x00,
185 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
186 DEFINE_GUID(MEDIASUBTYPE_Y800, 0x30303859, 0x0000, 0x0010, 0x80, 0x00,
187 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
189 DEFINE_GUID(CLSID_CaptureGraphBuilder2,0xbf87b6e1,0x8c27,0x11d0,0xb3,0xf0,0x00,0xaa,0x00,0x37,0x61,0xc5);
190 DEFINE_GUID(CLSID_FilterGraph,0xe436ebb3,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
191 DEFINE_GUID(CLSID_NullRenderer,0xc1f400a4,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37);
192 DEFINE_GUID(CLSID_SampleGrabber,0xc1f400a0,0x3f08,0x11d3,0x9f,0x0b,0x00,0x60,0x08,0x03,0x9e,0x37);
193 DEFINE_GUID(CLSID_SystemDeviceEnum,0x62be5d10,0x60eb,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
194 DEFINE_GUID(CLSID_VideoInputDeviceCategory,0x860bb310,0x5d01,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
195 DEFINE_GUID(FORMAT_VideoInfo,0x05589f80,0xc356,0x11ce,0xbf,0x01,0x00,0xaa,0x00,0x55,0x59,0x5a);
196 DEFINE_GUID(IID_IAMAnalogVideoDecoder,0xc6e13350,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
197 DEFINE_GUID(IID_IAMCameraControl,0xc6e13370,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
198 DEFINE_GUID(IID_IAMCrossbar,0xc6e13380,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
199 DEFINE_GUID(IID_IAMStreamConfig,0xc6e13340,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
200 DEFINE_GUID(IID_IAMVideoProcAmp,0xc6e13360,0x30ac,0x11d0,0xa1,0x8c,0x00,0xa0,0xc9,0x11,0x89,0x56);
201 DEFINE_GUID(IID_IBaseFilter,0x56a86895,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
202 DEFINE_GUID(IID_ICaptureGraphBuilder2,0x93e5a4e0,0x2d50,0x11d2,0xab,0xfa,0x00,0xa0,0xc9,0xc6,0xe3,0x8d);
203 DEFINE_GUID(IID_ICreateDevEnum,0x29840822,0x5b84,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9,0x11,0xce,0x86);
204 DEFINE_GUID(IID_IGraphBuilder,0x56a868a9,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
205 DEFINE_GUID(IID_IMPEG2PIDMap,0xafb6c2a1,0x2c41,0x11d3,0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a);
206 DEFINE_GUID(IID_IMediaControl,0x56a868b1,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
207 DEFINE_GUID(IID_IMediaFilter,0x56a86899,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
208 DEFINE_GUID(IID_ISampleGrabber,0x6b652fff,0x11fe,0x4fce,0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f);
209 DEFINE_GUID(LOOK_UPSTREAM_ONLY,0xac798be0,0x98e3,0x11d1,0xb3,0xf1,0x00,0xaa,0x00,0x37,0x61,0xc5);
210 DEFINE_GUID(MEDIASUBTYPE_AYUV,0x56555941,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
211 DEFINE_GUID(MEDIASUBTYPE_IYUV,0x56555949,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
212 DEFINE_GUID(MEDIASUBTYPE_RGB24,0xe436eb7d,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
213 DEFINE_GUID(MEDIASUBTYPE_RGB32,0xe436eb7e,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
214 DEFINE_GUID(MEDIASUBTYPE_RGB555,0xe436eb7c,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
215 DEFINE_GUID(MEDIASUBTYPE_RGB565,0xe436eb7b,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
216 DEFINE_GUID(MEDIASUBTYPE_I420,0x49343230,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
217 DEFINE_GUID(MEDIASUBTYPE_UYVY,0x59565955,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
218 DEFINE_GUID(MEDIASUBTYPE_Y211,0x31313259,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
219 DEFINE_GUID(MEDIASUBTYPE_Y411,0x31313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
220 DEFINE_GUID(MEDIASUBTYPE_Y41P,0x50313459,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
221 DEFINE_GUID(MEDIASUBTYPE_YUY2,0x32595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
222 DEFINE_GUID(MEDIASUBTYPE_YUYV,0x56595559,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
223 DEFINE_GUID(MEDIASUBTYPE_YV12,0x32315659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
224 DEFINE_GUID(MEDIASUBTYPE_YVU9,0x39555659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
225 DEFINE_GUID(MEDIASUBTYPE_YVYU,0x55595659,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
226 DEFINE_GUID(MEDIASUBTYPE_MJPG,0x47504A4D, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); // MGB
227 DEFINE_GUID(MEDIATYPE_Interleaved,0x73766169,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
228 DEFINE_GUID(MEDIATYPE_Video,0x73646976,0x0000,0x0010,0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71);
229 DEFINE_GUID(PIN_CATEGORY_CAPTURE,0xfb6c4281,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba);
230 DEFINE_GUID(PIN_CATEGORY_PREVIEW,0xfb6c4282,0x0353,0x11d1,0x90,0x5f,0x00,0x00,0xc0,0xcc,0x16,0xba);
232 interface ISampleGrabberCB : public IUnknown
234 virtual HRESULT STDMETHODCALLTYPE SampleCB(
236 IMediaSample *pSample) = 0;
238 virtual HRESULT STDMETHODCALLTYPE BufferCB(
243 virtual ~ISampleGrabberCB() {}
246 interface ISampleGrabber : public IUnknown
248 virtual HRESULT STDMETHODCALLTYPE SetOneShot(
251 virtual HRESULT STDMETHODCALLTYPE SetMediaType(
252 const AM_MEDIA_TYPE *pType) = 0;
254 virtual HRESULT STDMETHODCALLTYPE GetConnectedMediaType(
255 AM_MEDIA_TYPE *pType) = 0;
257 virtual HRESULT STDMETHODCALLTYPE SetBufferSamples(
258 BOOL BufferThem) = 0;
260 virtual HRESULT STDMETHODCALLTYPE GetCurrentBuffer(
264 virtual HRESULT STDMETHODCALLTYPE GetCurrentSample(
265 IMediaSample **ppSample) = 0;
267 virtual HRESULT STDMETHODCALLTYPE SetCallback(
268 ISampleGrabberCB *pCallback,
269 LONG WhichMethodToCallback) = 0;
271 virtual ~ISampleGrabber() {}
275 #define HEADER(p) (&(((VIDEOINFOHEADER*)(p))->bmiHeader))
280 //create a videoInput object
283 //Prints out a list of available devices and returns num of devices found
284 int numDevices = VI.listDevices();
286 int device1 = 0; //this could be any deviceID that shows up in listDevices
287 int device2 = 1; //this could be any deviceID that shows up in listDevices
289 //if you want to capture at a different frame rate (default is 30)
290 //specify it here, you are not guaranteed to get this fps though.
291 //VI.setIdealFramerate(dev, 60);
293 //setup the first device - there are a number of options:
295 VI.setupDevice(device1); //setup the first device with the default settings
296 //VI.setupDevice(device1, VI_COMPOSITE); //or setup device with specific connection type
297 //VI.setupDevice(device1, 320, 240); //or setup device with specified video size
298 //VI.setupDevice(device1, 320, 240, VI_COMPOSITE); //or setup device with video size and connection type
300 //VI.setFormat(device1, VI_NTSC_M); //if your card doesn't remember what format it should be
301 //call this with the appropriate format listed above
302 //NOTE: must be called after setupDevice!
304 //optionally setup a second (or third, fourth ...) device - same options as above
305 VI.setupDevice(device2);
307 //As requested width and height can not always be accomodated
308 //make sure to check the size once the device is setup
310 int width = VI.getWidth(device1);
311 int height = VI.getHeight(device1);
312 int size = VI.getSize(device1);
314 unsigned char * yourBuffer1 = new unsigned char[size];
315 unsigned char * yourBuffer2 = new unsigned char[size];
317 //to get the data from the device first check if the data is new
318 if(VI.isFrameNew(device1)){
319 VI.getPixels(device1, yourBuffer1, false, false); //fills pixels as a BGR (for openCV) unsigned char array - no flipping
320 VI.getPixels(device1, yourBuffer2, true, true); //fills pixels as a RGB (for openGL) unsigned char array - flipping!
323 //same applies to device2 etc
325 //to get a settings dialog for the device
326 VI.showSettingsWindow(device1);
329 //Shut down devices properly
330 VI.stopDevice(device1);
331 VI.stopDevice(device2);
335 ////////////////////////////////////// VARS AND DEFS //////////////////////////////////
338 //STUFF YOU CAN CHANGE
340 //change for verbose debug info
341 static bool verbose = true;
343 //if you need VI to use multi threaded com
344 //#define VI_COM_MULTI_THREADED
346 //STUFF YOU DON'T CHANGE
349 #define VI_VERSION 0.1995
350 #define VI_MAX_CAMERAS 20
351 #define VI_NUM_TYPES 20 //MGB
352 #define VI_NUM_FORMATS 18 //DON'T TOUCH
354 //defines for setPhyCon - tuner is not as well supported as composite and s-video
355 #define VI_COMPOSITE 0
361 //defines for formats
372 #define VI_SECAM_D 10
373 #define VI_SECAM_G 11
374 #define VI_SECAM_H 12
375 #define VI_SECAM_K 13
376 #define VI_SECAM_K1 14
377 #define VI_SECAM_L 15
378 #define VI_NTSC_M_J 16
379 #define VI_NTSC_433 17
382 //allows us to directShow classes here with the includes in the cpp
383 struct ICaptureGraphBuilder2;
384 struct IGraphBuilder;
387 struct IMediaControl;
388 struct ISampleGrabber;
389 struct IMediaEventEx;
390 struct IAMStreamConfig;
392 class SampleGrabberCallback;
393 typedef _AMMediaType AM_MEDIA_TYPE;
395 //keeps track of how many instances of VI are being used
397 //static int comInitCount = 0;
400 //////////////////////////////////////// VIDEO DEVICE ///////////////////////////////////
408 void setSize(int w, int h);
409 void NukeDownstream(IBaseFilter *pBF);
421 ICaptureGraphBuilder2 *pCaptureGraph; // Capture graph builder object
422 IGraphBuilder *pGraph; // Graph builder object
423 IMediaControl *pControl; // Media control object
424 IBaseFilter *pVideoInputFilter; // Video Capture filter
425 IBaseFilter *pGrabberF;
426 IBaseFilter * pDestFilter;
427 IAMStreamConfig *streamConf;
428 ISampleGrabber * pGrabber; // Grabs frame
429 AM_MEDIA_TYPE * pAmMediaType;
431 IMediaEventEx * pMediaEvent;
436 SampleGrabberCallback * sgCallback;
445 int nFramesForReconnect;
446 unsigned long nFramesRunning;
450 long requestedFrameTime; //ie fps
452 char nDeviceName[255];
453 WCHAR wDeviceName[255];
455 unsigned char * pixels;
463 ////////////////////////////////////// VIDEO INPUT /////////////////////////////////////
473 //turns off console messages - default is to print messages
474 static void setVerbose(bool _verbose);
476 //Functions in rough order they should be used.
477 static int listDevices(bool silent = false);
479 //needs to be called after listDevices - otherwise returns NULL
480 static char * getDeviceName(int deviceID);
482 //choose to use callback based capture - or single threaded
483 void setUseCallback(bool useCallback);
485 //call before setupDevice
486 //directshow will try and get the closest possible framerate to what is requested
487 void setIdealFramerate(int deviceID, int idealFramerate);
489 //some devices will stop delivering frames after a while - this method gives you the option to try and reconnect
490 //to a device if videoInput detects that a device has stopped delivering frames.
491 //you MUST CALL isFrameNew every app loop for this to have any effect
492 void setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect);
494 //Choose one of these five to setup your device
495 bool setupDevice(int deviceID);
496 bool setupDevice(int deviceID, int w, int h);
497 bool setupDeviceFourcc(int deviceID, int w, int h,int fourcc);
499 //These two are only for capture cards
500 //USB and Firewire cameras souldn't specify connection
501 bool setupDevice(int deviceID, int connection);
502 bool setupDevice(int deviceID, int w, int h, int connection);
504 bool setFourcc(int deviceNumber, int fourcc);
506 //If you need to you can set your NTSC/PAL/SECAM
507 //preference here. if it is available it will be used.
508 //see #defines above for available formats - eg VI_NTSC_M or VI_PAL_B
509 //should be called after setupDevice
510 //can be called multiple times
511 bool setFormat(int deviceNumber, int format);
513 //Tells you when a new frame has arrived - you should call this if you have specified setAutoReconnectOnFreeze to true
514 bool isFrameNew(int deviceID);
516 bool isDeviceSetup(int deviceID);
518 //Returns the pixels - flipRedAndBlue toggles RGB/BGR flipping - and you can flip the image too
519 unsigned char * getPixels(int deviceID, bool flipRedAndBlue = true, bool flipImage = false);
521 //Or pass in a buffer for getPixels to fill returns true if successful.
522 bool getPixels(int id, unsigned char * pixels, bool flipRedAndBlue = true, bool flipImage = false);
524 //Launches a pop up settings window
525 //For some reason in GLUT you have to call it twice each time.
526 void showSettingsWindow(int deviceID);
528 //Manual control over settings thanks.....
529 //These are experimental for now.
530 bool setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false);
531 bool setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags = 0);
532 bool getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue);
534 bool setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags = 0, bool useDefaultValue = false);
535 bool setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags = 0);
536 bool getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue);
538 //bool setVideoSettingCam(int deviceID, long Property, long lValue, long Flags = NULL, bool useDefaultValue = false);
540 //get width, height and number of pixels
541 int getWidth(int deviceID);
542 int getHeight(int deviceID);
543 int getSize(int deviceID);
544 int getFourcc(int deviceID);
545 double getFPS(int deviceID);
547 //completely stops and frees a device
548 void stopDevice(int deviceID);
550 //as above but then sets it up with same settings
551 bool restartDevice(int deviceID);
553 //number of devices available
556 // mapping from OpenCV CV_CAP_PROP to videoinput/dshow properties
557 int getVideoPropertyFromCV(int cv_property);
558 int getCameraPropertyFromCV(int cv_property);
561 void setPhyCon(int deviceID, int conn);
562 void setAttemptCaptureSize(int deviceID, int w, int h,GUID mediaType=MEDIASUBTYPE_RGB24);
563 bool setup(int deviceID);
564 void processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip);
565 int start(int deviceID, videoDevice * VD);
566 int getDeviceCount();
567 void getMediaSubtypeAsString(GUID type, char * typeAsString);
568 GUID *getMediaSubtypeFromFourcc(int fourcc);
569 int getFourccFromMediaSubtype(GUID type);
571 void getVideoPropertyAsString(int prop, char * propertyAsString);
572 void getCameraPropertyAsString(int prop, char * propertyAsString);
574 HRESULT getDevice(IBaseFilter **pSrcFilter, int deviceID, WCHAR * wDeviceName, char * nDeviceName);
575 static HRESULT ShowFilterPropertyPages(IBaseFilter *pFilter);
576 static HRESULT ShowStreamPropertyPages(IAMStreamConfig *pStream);
578 HRESULT SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath);
579 HRESULT routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode);
582 static bool comInit();
583 static bool comUnInit();
586 int callbackSetCount;
591 //Extra video subtypes
592 GUID MEDIASUBTYPE_Y800;
593 GUID MEDIASUBTYPE_Y8;
594 GUID MEDIASUBTYPE_GREY;
596 videoDevice * VDList[VI_MAX_CAMERAS];
597 GUID mediaSubtypes[VI_NUM_TYPES];
598 long formatTypes[VI_NUM_FORMATS];
600 static void __cdecl basicThread(void * objPtr);
602 static char deviceNames[VI_MAX_CAMERAS][255];
606 /////////////////////////// HANDY FUNCTIONS /////////////////////////////
608 static void MyFreeMediaType(AM_MEDIA_TYPE& mt){
609 if (mt.cbFormat != 0)
611 CoTaskMemFree((PVOID)mt.pbFormat);
617 // Unecessary because pUnk should not be used, but safest.
623 static void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
627 MyFreeMediaType(*pmt);
632 ////////////////////////////// CALLBACK ////////////////////////////////
635 class SampleGrabberCallback : public ISampleGrabberCB{
638 //------------------------------------------------
639 SampleGrabberCallback(){
640 InitializeCriticalSection(&critSection);
646 latestBufferLength = 0;
648 hEvent = CreateEvent(NULL, true, false, NULL);
652 //------------------------------------------------
653 virtual ~SampleGrabberCallback(){
655 DeleteCriticalSection(&critSection);
663 //------------------------------------------------
664 bool setupBuffer(int numBytesIn){
668 numBytes = numBytesIn;
669 pixels = new unsigned char[numBytes];
672 latestBufferLength = 0;
678 //------------------------------------------------
679 STDMETHODIMP_(ULONG) AddRef() { return 1; }
680 STDMETHODIMP_(ULONG) Release() { return 2; }
683 //------------------------------------------------
684 STDMETHODIMP QueryInterface(REFIID, void **ppvObject){
685 *ppvObject = static_cast<ISampleGrabberCB*>(this);
690 //This method is meant to have less overhead
691 //------------------------------------------------
692 STDMETHODIMP SampleCB(double , IMediaSample *pSample){
693 if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) return S_OK;
695 HRESULT hr = pSample->GetPointer(&ptrBuffer);
698 latestBufferLength = pSample->GetActualDataLength();
699 if(latestBufferLength == numBytes){
700 EnterCriticalSection(&critSection);
701 memcpy(pixels, ptrBuffer, latestBufferLength);
704 LeaveCriticalSection(&critSection);
707 printf("ERROR: SampleCB() - buffer sizes do not match\n");
715 //This method is meant to have more overhead
716 STDMETHODIMP BufferCB(double, BYTE *, long){
722 int latestBufferLength;
726 unsigned char * pixels;
727 unsigned char * ptrBuffer;
728 CRITICAL_SECTION critSection;
733 ////////////////////////////// VIDEO DEVICE ////////////////////////////////
735 // ----------------------------------------------------------------------
736 // Should this class also be the callback?
738 // ----------------------------------------------------------------------
740 videoDevice::videoDevice(){
742 pCaptureGraph = NULL; // Capture graph builder object
743 pGraph = NULL; // Graph builder object
744 pControl = NULL; // Media control object
745 pVideoInputFilter = NULL; // Video Capture filter
746 pGrabber = NULL; // Grabs frame
747 pDestFilter = NULL; // Null Renderer Filter
748 pGrabberF = NULL; // Grabber Filter
753 //This is our callback class that processes the frame.
754 sgCallback = new SampleGrabberCallback();
755 sgCallback->newFrame = false;
757 //Default values for capture type
758 videoType = MEDIASUBTYPE_RGB24;
759 connection = PhysConn_Video_Composite;
768 tryVideoType = MEDIASUBTYPE_RGB24;
769 nFramesForReconnect= 10000;
775 readyToCapture = false;
777 setupStarted = false;
778 specificFormat = false;
779 autoReconnect = false;
780 requestedFrameTime = -1;
782 memset(wDeviceName, 0, sizeof(WCHAR) * 255);
783 memset(nDeviceName, 0, sizeof(char) * 255);
788 // ----------------------------------------------------------------------
789 // The only place we are doing new
791 // ----------------------------------------------------------------------
793 void videoDevice::setSize(int w, int h){
795 if(verbose)printf("SETUP: Error device size should not be set more than once \n");
803 pixels = new unsigned char[videoSize];
804 pBuffer = new char[videoSize];
806 memset(pixels, 0 , videoSize);
807 sgCallback->setupBuffer(videoSize);
813 // ----------------------------------------------------------------------
814 // Borrowed from the SDK, use it to take apart the graph from
815 // the capture device downstream to the null renderer
816 // ----------------------------------------------------------------------
818 void videoDevice::NukeDownstream(IBaseFilter *pBF){
821 IEnumPins *pins = NULL;
823 HRESULT hr = pBF->EnumPins(&pins);
825 while (hr == NOERROR)
827 hr = pins->Next(1, &pP, &u);
828 if (hr == S_OK && pP)
830 pP->ConnectedTo(&pTo);
833 hr = pTo->QueryPinInfo(&pininfo);
836 if (pininfo.dir == PINDIR_INPUT)
838 NukeDownstream(pininfo.pFilter);
839 pGraph->Disconnect(pTo);
840 pGraph->Disconnect(pP);
841 pGraph->RemoveFilter(pininfo.pFilter);
843 pininfo.pFilter->Release();
844 pininfo.pFilter = NULL;
851 if (pins) pins->Release();
855 // ----------------------------------------------------------------------
857 // ----------------------------------------------------------------------
859 void videoDevice::destroyGraph(){
865 while (hr == NOERROR)
867 IEnumFilters * pEnum = 0;
870 // We must get the enumerator again every time because removing a filter from the graph
871 // invalidates the enumerator. We always get only the first filter from each enumerator.
872 hr = pGraph->EnumFilters(&pEnum);
873 if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->EnumFilters() failed. \n"); return; }
875 IBaseFilter * pFilter = NULL;
876 if (pEnum->Next(1, &pFilter, &cFetched) == S_OK)
878 FILTER_INFO FilterInfo;
879 memset(&FilterInfo, 0, sizeof(FilterInfo));
880 hr = pFilter->QueryFilterInfo(&FilterInfo);
881 FilterInfo.pGraph->Release();
885 memset(buffer, 0, 255 * sizeof(char));
887 while( FilterInfo.achName[count] != 0x00 )
889 buffer[count] = (char)FilterInfo.achName[count];
893 if(verbose)printf("SETUP: removing filter %s...\n", buffer);
894 hr = pGraph->RemoveFilter(pFilter);
895 if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->RemoveFilter() failed. \n"); return; }
896 if(verbose)printf("SETUP: filter removed %s \n",buffer);
911 // ----------------------------------------------------------------------
912 // Our deconstructor, attempts to tear down graph and release filters etc
913 // Does checking to make sure it only is freeing if it needs to
914 // Probably could be a lot cleaner! :)
915 // ----------------------------------------------------------------------
917 videoDevice::~videoDevice(){
919 if(setupStarted){ if(verbose)printf("\nSETUP: Disconnecting device %i\n", myID); }
922 sgCallback->Release();
928 HRESULT HR = NOERROR;
930 //Stop the callback and free it
931 if( (sgCallback) && (pGrabber) )
933 pGrabber->SetCallback(NULL, 1);
934 if(verbose)printf("SETUP: freeing Grabber Callback\n");
935 sgCallback->Release();
946 //Check to see if the graph is running, if so stop it.
949 HR = pControl->Pause();
950 if (FAILED(HR)) if(verbose)printf("ERROR - Could not pause pControl\n");
952 HR = pControl->Stop();
953 if (FAILED(HR)) if(verbose)printf("ERROR - Could not stop pControl\n");
956 //Disconnect filters from capture device
957 if( (pVideoInputFilter) )NukeDownstream(pVideoInputFilter);
959 //Release and zero pointers to our filters etc
960 if( (pDestFilter) ){ if(verbose)printf("SETUP: freeing Renderer \n");
961 (pDestFilter)->Release();
964 if( (pVideoInputFilter) ){ if(verbose)printf("SETUP: freeing Capture Source \n");
965 (pVideoInputFilter)->Release();
966 (pVideoInputFilter) = 0;
968 if( (pGrabberF) ){ if(verbose)printf("SETUP: freeing Grabber Filter \n");
969 (pGrabberF)->Release();
972 if( (pGrabber) ){ if(verbose)printf("SETUP: freeing Grabber \n");
973 (pGrabber)->Release();
976 if( (pControl) ){ if(verbose)printf("SETUP: freeing Control \n");
977 (pControl)->Release();
980 if( (pMediaEvent) ){ if(verbose)printf("SETUP: freeing Media Event \n");
981 (pMediaEvent)->Release();
984 if( (streamConf) ){ if(verbose)printf("SETUP: freeing Stream \n");
985 (streamConf)->Release();
989 if( (pAmMediaType) ){ if(verbose)printf("SETUP: freeing Media Type \n");
990 MyDeleteMediaType(pAmMediaType);
994 if(verbose)printf("SETUP: freeing Media Event \n");
995 (pMediaEvent)->Release();
1000 if( (pGraph) )destroyGraph();
1002 //Release and zero our capture graph and our main graph
1003 if( (pCaptureGraph) ){ if(verbose)printf("SETUP: freeing Capture Graph \n");
1004 (pCaptureGraph)->Release();
1005 (pCaptureGraph) = 0;
1007 if( (pGraph) ){ if(verbose)printf("SETUP: freeing Main Graph \n");
1008 (pGraph)->Release();
1012 //delete our pointers
1014 delete pVideoInputFilter;
1020 delete pCaptureGraph;
1023 if(verbose)printf("SETUP: Device %i disconnected and freed\n\n",myID);
1027 ////////////////////////////// VIDEO INPUT ////////////////////////////////
1028 //////////////////////////// PUBLIC METHODS ///////////////////////////////
1031 // ----------------------------------------------------------------------
1032 // Constructor - creates instances of videoDevice and adds the various
1033 // media subtypes to check.
1034 // ----------------------------------------------------------------------
1036 videoInput::videoInput(){
1041 callbackSetCount = 0;
1044 //setup a max no of device objects
1045 for(int i=0; i<VI_MAX_CAMERAS; i++) VDList[i] = new videoDevice();
1047 if(verbose)printf("\n***** VIDEOINPUT LIBRARY - %2.04f - TFW07 *****\n\n",VI_VERSION);
1049 //added for the pixelink firewire camera
1050 //MEDIASUBTYPE_Y800 = (GUID)FOURCCMap(FCC('Y800'));
1051 //MEDIASUBTYPE_Y8 = (GUID)FOURCCMap(FCC('Y8'));
1052 //MEDIASUBTYPE_GREY = (GUID)FOURCCMap(FCC('GREY'));
1054 //The video types we support
1055 //in order of preference
1057 mediaSubtypes[0] = MEDIASUBTYPE_RGB24;
1058 mediaSubtypes[1] = MEDIASUBTYPE_RGB32;
1059 mediaSubtypes[2] = MEDIASUBTYPE_RGB555;
1060 mediaSubtypes[3] = MEDIASUBTYPE_RGB565;
1061 mediaSubtypes[4] = MEDIASUBTYPE_YUY2;
1062 mediaSubtypes[5] = MEDIASUBTYPE_YVYU;
1063 mediaSubtypes[6] = MEDIASUBTYPE_YUYV;
1064 mediaSubtypes[7] = MEDIASUBTYPE_IYUV;
1065 mediaSubtypes[8] = MEDIASUBTYPE_UYVY;
1066 mediaSubtypes[9] = MEDIASUBTYPE_YV12;
1067 mediaSubtypes[10] = MEDIASUBTYPE_YVU9;
1068 mediaSubtypes[11] = MEDIASUBTYPE_Y411;
1069 mediaSubtypes[12] = MEDIASUBTYPE_Y41P;
1070 mediaSubtypes[13] = MEDIASUBTYPE_Y211;
1071 mediaSubtypes[14] = MEDIASUBTYPE_AYUV;
1072 mediaSubtypes[15] = MEDIASUBTYPE_MJPG; // MGB
1075 mediaSubtypes[16] = MEDIASUBTYPE_Y800;
1076 mediaSubtypes[17] = MEDIASUBTYPE_Y8;
1077 mediaSubtypes[18] = MEDIASUBTYPE_GREY;
1078 mediaSubtypes[19] = MEDIASUBTYPE_I420;
1080 //The video formats we support
1081 formatTypes[VI_NTSC_M] = AnalogVideo_NTSC_M;
1082 formatTypes[VI_NTSC_M_J] = AnalogVideo_NTSC_M_J;
1083 formatTypes[VI_NTSC_433] = AnalogVideo_NTSC_433;
1085 formatTypes[VI_PAL_B] = AnalogVideo_PAL_B;
1086 formatTypes[VI_PAL_D] = AnalogVideo_PAL_D;
1087 formatTypes[VI_PAL_G] = AnalogVideo_PAL_G;
1088 formatTypes[VI_PAL_H] = AnalogVideo_PAL_H;
1089 formatTypes[VI_PAL_I] = AnalogVideo_PAL_I;
1090 formatTypes[VI_PAL_M] = AnalogVideo_PAL_M;
1091 formatTypes[VI_PAL_N] = AnalogVideo_PAL_N;
1092 formatTypes[VI_PAL_NC] = AnalogVideo_PAL_N_COMBO;
1094 formatTypes[VI_SECAM_B] = AnalogVideo_SECAM_B;
1095 formatTypes[VI_SECAM_D] = AnalogVideo_SECAM_D;
1096 formatTypes[VI_SECAM_G] = AnalogVideo_SECAM_G;
1097 formatTypes[VI_SECAM_H] = AnalogVideo_SECAM_H;
1098 formatTypes[VI_SECAM_K] = AnalogVideo_SECAM_K;
1099 formatTypes[VI_SECAM_K1] = AnalogVideo_SECAM_K1;
1100 formatTypes[VI_SECAM_L] = AnalogVideo_SECAM_L;
1105 // ----------------------------------------------------------------------
1106 // static - set whether messages get printed to console or not
1108 // ----------------------------------------------------------------------
1110 void videoInput::setVerbose(bool _verbose){
1114 // ----------------------------------------------------------------------
1115 // change to use callback or regular capture
1116 // callback tells you when a new frame has arrived
1117 // but non-callback won't - but is single threaded
1118 // ----------------------------------------------------------------------
1119 void videoInput::setUseCallback(bool useCallback){
1120 if(callbackSetCount == 0){
1121 bCallback = useCallback;
1122 callbackSetCount = 1;
1124 printf("ERROR: setUseCallback can only be called before setup\n");
1128 // ----------------------------------------------------------------------
1129 // Set the requested framerate - no guarantee you will get this
1131 // ----------------------------------------------------------------------
1133 void videoInput::setIdealFramerate(int deviceNumber, int idealFramerate){
1134 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return;
1136 if( idealFramerate > 0 ){
1137 VDList[deviceNumber]->requestedFrameTime = (unsigned long)(10000000 / idealFramerate);
1142 // ----------------------------------------------------------------------
1143 // Set the requested framerate - no guarantee you will get this
1145 // ----------------------------------------------------------------------
1147 void videoInput::setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect){
1148 if(deviceNumber >= VI_MAX_CAMERAS) return;
1150 VDList[deviceNumber]->autoReconnect = doReconnect;
1151 VDList[deviceNumber]->nFramesForReconnect = numMissedFramesBeforeReconnect;
1156 // ----------------------------------------------------------------------
1157 // Setup a device with the default settings
1159 // ----------------------------------------------------------------------
1161 bool videoInput::setupDevice(int deviceNumber){
1162 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1164 if(setup(deviceNumber))return true;
1169 // ----------------------------------------------------------------------
1170 // Setup a device with the default size but specify input type
1172 // ----------------------------------------------------------------------
1174 bool videoInput::setupDevice(int deviceNumber, int _connection){
1175 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1177 setPhyCon(deviceNumber, _connection);
1178 if(setup(deviceNumber))return true;
1183 // ----------------------------------------------------------------------
1184 // Setup a device with the default connection but specify size
1186 // ----------------------------------------------------------------------
1188 bool videoInput::setupDevice(int deviceNumber, int w, int h){
1189 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1191 setAttemptCaptureSize(deviceNumber,w,h);
1192 if(setup(deviceNumber))return true;
1196 // ----------------------------------------------------------------------
1197 // Setup a device with the default connection but specify size and image format
1200 // Need a new name for this since signature clashes with ",int connection)"
1201 // ----------------------------------------------------------------------
1203 bool videoInput::setupDeviceFourcc(int deviceNumber, int w, int h,int fourcc){
1204 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1206 if ( fourcc != -1 ) {
1207 GUID *mediaType = getMediaSubtypeFromFourcc(fourcc);
1209 setAttemptCaptureSize(deviceNumber,w,h,*mediaType);
1212 setAttemptCaptureSize(deviceNumber,w,h);
1214 if(setup(deviceNumber))return true;
1219 // ----------------------------------------------------------------------
1220 // Setup a device with specific size and connection
1222 // ----------------------------------------------------------------------
1224 bool videoInput::setupDevice(int deviceNumber, int w, int h, int _connection){
1225 if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
1227 setAttemptCaptureSize(deviceNumber,w,h);
1228 setPhyCon(deviceNumber, _connection);
1229 if(setup(deviceNumber))return true;
1234 // ----------------------------------------------------------------------
1235 // Setup the default video format of the device
1236 // Must be called after setup!
1237 // See #define formats in header file (eg VI_NTSC_M )
1239 // ----------------------------------------------------------------------
1241 bool videoInput::setFormat(int deviceNumber, int format){
1242 if(deviceNumber >= VI_MAX_CAMERAS || !VDList[deviceNumber]->readyToCapture) return false;
1244 bool returnVal = false;
1246 if(format >= 0 && format < VI_NUM_FORMATS){
1247 VDList[deviceNumber]->formatType = formatTypes[format];
1248 VDList[deviceNumber]->specificFormat = true;
1250 if(VDList[deviceNumber]->specificFormat){
1252 HRESULT hr = getDevice(&VDList[deviceNumber]->pVideoInputFilter, deviceNumber, VDList[deviceNumber]->wDeviceName, VDList[deviceNumber]->nDeviceName);
1257 IAMAnalogVideoDecoder *pVideoDec = NULL;
1258 hr = VDList[deviceNumber]->pCaptureGraph->FindInterface(NULL, &MEDIATYPE_Video, VDList[deviceNumber]->pVideoInputFilter, IID_IAMAnalogVideoDecoder, (void **)&pVideoDec);
1261 //in case the settings window some how freed them first
1262 if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter->Release();
1263 if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter = NULL;
1266 printf("SETUP: couldn't set requested format\n");
1269 hr = pVideoDec->get_AvailableTVFormats(&lValue);
1270 if( SUCCEEDED(hr) && (lValue & VDList[deviceNumber]->formatType) )
1272 hr = pVideoDec->put_TVFormat(VDList[deviceNumber]->formatType);
1274 printf("SETUP: couldn't set requested format\n");
1280 pVideoDec->Release();
1289 // ----------------------------------------------------------------------
1290 // Our static function for returning device names - thanks Peter!
1291 // Must call listDevices first.
1293 // ----------------------------------------------------------------------
1294 char videoInput::deviceNames[VI_MAX_CAMERAS][255]={{0}};
1296 char * videoInput::getDeviceName(int deviceID){
1297 if( deviceID >= VI_MAX_CAMERAS ){
1300 return deviceNames[deviceID];
1304 // ----------------------------------------------------------------------
1305 // Our static function for finding num devices available etc
1307 // ----------------------------------------------------------------------
1309 int videoInput::listDevices(bool silent){
1311 //COM Library Intialization
1314 if(!silent)printf("\nVIDEOINPUT SPY MODE!\n\n");
1317 ICreateDevEnum *pDevEnum = NULL;
1318 IEnumMoniker *pEnum = NULL;
1319 int deviceCounter = 0;
1321 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
1322 CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
1323 reinterpret_cast<void**>(&pDevEnum));
1328 // Create an enumerator for the video capture category.
1329 hr = pDevEnum->CreateClassEnumerator(
1330 CLSID_VideoInputDeviceCategory,
1335 if(!silent)printf("SETUP: Looking For Capture Devices\n");
1336 IMoniker *pMoniker = NULL;
1338 while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
1340 IPropertyBag *pPropBag;
1341 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
1342 (void**)(&pPropBag));
1345 pMoniker->Release();
1346 continue; // Skip this one, maybe the next one will work.
1350 // Find the description or friendly name.
1352 VariantInit(&varName);
1353 hr = pPropBag->Read(L"Description", &varName, 0);
1355 if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);
1359 hr = pPropBag->Read(L"FriendlyName", &varName, 0);
1362 int maxLen = sizeof(deviceNames[0])/sizeof(deviceNames[0][0]) - 2;
1363 while( varName.bstrVal[count] != 0x00 && count < maxLen) {
1364 deviceNames[deviceCounter][count] = (char)varName.bstrVal[count];
1367 deviceNames[deviceCounter][count] = 0;
1369 if(!silent)printf("SETUP: %i) %s \n",deviceCounter, deviceNames[deviceCounter]);
1372 pPropBag->Release();
1375 pMoniker->Release();
1381 pDevEnum->Release();
1388 if(!silent)printf("SETUP: %i Device(s) found\n\n", deviceCounter);
1393 return deviceCounter;
1397 // ----------------------------------------------------------------------
1400 // ----------------------------------------------------------------------
1402 int videoInput::getWidth(int id){
1404 if(isDeviceSetup(id))
1406 return VDList[id] ->width;
1414 // ----------------------------------------------------------------------
1417 // ----------------------------------------------------------------------
1419 int videoInput::getHeight(int id){
1421 if(isDeviceSetup(id))
1423 return VDList[id] ->height;
1430 // ----------------------------------------------------------------------
1433 // ----------------------------------------------------------------------
1434 int videoInput::getFourcc(int id){
1436 if(isDeviceSetup(id))
1438 return getFourccFromMediaSubtype(VDList[id]->videoType);
1445 double videoInput::getFPS(int id){
1447 if(isDeviceSetup(id))
1449 double frameTime= VDList[id]->requestedFrameTime;
1451 return (10000000.0 / frameTime);
1460 // ----------------------------------------------------------------------
1463 // ----------------------------------------------------------------------
1465 int videoInput::getSize(int id){
1467 if(isDeviceSetup(id))
1469 return VDList[id] ->videoSize;
1477 // ----------------------------------------------------------------------
1478 // Uses a supplied buffer
1479 // ----------------------------------------------------------------------
1481 bool videoInput::getPixels(int id, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage){
1483 bool success = false;
1485 if(isDeviceSetup(id)){
1489 DWORD result = WaitForSingleObject(VDList[id]->sgCallback->hEvent, 1000);
1490 if( result != WAIT_OBJECT_0) return false;
1492 //double paranoia - mutexing with both event and critical section
1493 EnterCriticalSection(&VDList[id]->sgCallback->critSection);
1495 unsigned char * src = VDList[id]->sgCallback->pixels;
1496 unsigned char * dst = dstBuffer;
1497 int height = VDList[id]->height;
1498 int width = VDList[id]->width;
1500 processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
1501 VDList[id]->sgCallback->newFrame = false;
1503 LeaveCriticalSection(&VDList[id]->sgCallback->critSection);
1505 ResetEvent(VDList[id]->sgCallback->hEvent);
1511 //regular capture method
1512 long bufferSize = VDList[id]->videoSize;
1513 HRESULT hr = VDList[id]->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VDList[id]->pBuffer);
1515 int numBytes = VDList[id]->videoSize;
1516 if (numBytes == bufferSize){
1518 unsigned char * src = (unsigned char * )VDList[id]->pBuffer;
1519 unsigned char * dst = dstBuffer;
1520 int height = VDList[id]->height;
1521 int width = VDList[id]->width;
1523 processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
1526 if(verbose)printf("ERROR: GetPixels() - bufferSizes do not match!\n");
1529 if(verbose)printf("ERROR: GetPixels() - Unable to grab frame for device %i\n", id);
1538 // ----------------------------------------------------------------------
1540 // ----------------------------------------------------------------------
1541 unsigned char * videoInput::getPixels(int id, bool flipRedAndBlue, bool flipImage){
1543 if(isDeviceSetup(id)){
1544 getPixels(id, VDList[id]->pixels, flipRedAndBlue, flipImage);
1547 return VDList[id]->pixels;
1552 // ----------------------------------------------------------------------
1555 // ----------------------------------------------------------------------
1556 bool videoInput::isFrameNew(int id){
1557 if(!isDeviceSetup(id)) return false;
1558 if(!bCallback)return true;
1560 bool result = false;
1561 bool freeze = false;
1563 //again super paranoia!
1564 EnterCriticalSection(&VDList[id]->sgCallback->critSection);
1565 result = VDList[id]->sgCallback->newFrame;
1567 //we need to give it some time at the begining to start up so lets check after 400 frames
1568 if(VDList[id]->nFramesRunning > 400 && VDList[id]->sgCallback->freezeCheck > VDList[id]->nFramesForReconnect ){
1572 //we increment the freezeCheck var here - the callback resets it to 1
1573 //so as long as the callback is running this var should never get too high.
1574 //if the callback is not running then this number will get high and trigger the freeze action below
1575 VDList[id]->sgCallback->freezeCheck++;
1576 LeaveCriticalSection(&VDList[id]->sgCallback->critSection);
1578 VDList[id]->nFramesRunning++;
1580 if(freeze && VDList[id]->autoReconnect){
1581 if(verbose)printf("ERROR: Device seems frozen - attempting to reconnect\n");
1582 if( !restartDevice(VDList[id]->myID) ){
1583 if(verbose)printf("ERROR: Unable to reconnect to device\n");
1585 if(verbose)printf("SUCCESS: Able to reconnect to device\n");
1593 // ----------------------------------------------------------------------
1596 // ----------------------------------------------------------------------
1598 bool videoInput::isDeviceSetup(int id){
1600 if(id<devicesFound && VDList[id]->readyToCapture)return true;
1606 // ----------------------------------------------------------------------
1607 // Gives us a little pop up window to adjust settings
1608 // We do this in a seperate thread now!
1609 // ----------------------------------------------------------------------
1612 void __cdecl videoInput::basicThread(void * objPtr){
1614 //get a reference to the video device
1615 //not a copy as we need to free the filter
1616 videoDevice * vd = *( (videoDevice **)(objPtr) );
1617 ShowFilterPropertyPages(vd->pVideoInputFilter);
1621 //now we free the filter and make sure it set to NULL
1622 if(vd->pVideoInputFilter)vd->pVideoInputFilter->Release();
1623 if(vd->pVideoInputFilter)vd->pVideoInputFilter = NULL;
1628 void videoInput::showSettingsWindow(int id){
1630 if(isDeviceSetup(id)){
1631 //HANDLE myTempThread;
1633 //we reconnect to the device as we have freed our reference to it
1634 //why have we freed our reference? because there seemed to be an issue
1635 //with some mpeg devices if we didn't
1636 HRESULT hr = getDevice(&VDList[id]->pVideoInputFilter, id, VDList[id]->wDeviceName, VDList[id]->nDeviceName);
1638 //myTempThread = (HANDLE)
1639 _beginthread(basicThread, 0, (void *)&VDList[id]);
1645 // Set a video signal setting using IAMVideoProcAmp
1646 bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue){
1647 if( !isDeviceSetup(deviceID) )return false;
1650 //bool isSuccessful = false;
1652 videoDevice * VD = VDList[deviceID];
1654 hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1656 printf("setVideoSetting - getDevice Error\n");
1660 IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1662 hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1664 printf("setVideoSetting - QueryInterface Error\n");
1665 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1666 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1671 getVideoPropertyAsString(Property,propStr);
1673 if (verbose) printf("Setting video setting %s.\n", propStr);
1675 pAMVideoProcAmp->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1676 if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags);
1677 pAMVideoProcAmp->Get(Property, ¤tValue, &flags);
1679 if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1680 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1681 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1688 // Set a video signal setting using IAMVideoProcAmp
1689 bool videoInput::setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags){
1690 if( !isDeviceSetup(deviceID) )return false;
1692 long min, max, currentValue, flags, defaultValue, stepAmnt;
1694 if( !getVideoSettingFilter(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1696 if(pctValue > 1.0)pctValue = 1.0;
1697 else if(pctValue < 0)pctValue = 0.0;
1699 float range = (float)max - (float)min;
1700 if(range <= 0)return false;
1701 if(stepAmnt == 0) return false;
1703 long value = (long)( (float)min + range * pctValue );
1704 long rasterValue = value;
1706 //if the range is the stepAmnt then it is just a switch
1707 //so we either set the value to low or high
1708 if( range == stepAmnt ){
1709 if( pctValue < 0.5)rasterValue = min;
1710 else rasterValue = max;
1712 //we need to rasterize the value to the stepping amnt
1713 long mod = value % stepAmnt;
1714 float halfStep = (float)stepAmnt * 0.5f;
1715 if( mod < halfStep ) rasterValue -= mod;
1716 else rasterValue += stepAmnt - mod;
1717 printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue);
1720 return setVideoSettingFilter(deviceID, Property, rasterValue, Flags, false);
1724 // Set a video signal setting using IAMVideoProcAmp
1725 bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1726 if( !isDeviceSetup(deviceID) )return false;
1729 //bool isSuccessful = false;
1732 getVideoPropertyAsString(Property,propStr);
1734 videoDevice * VD = VDList[deviceID];
1736 hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1738 printf("setVideoSetting - getDevice Error\n");
1742 IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1744 hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1746 printf("setVideoSetting - QueryInterface Error\n");
1747 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1748 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1752 if (verbose) printf("Setting video setting %s.\n", propStr);
1753 long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags = 0;
1756 pAMVideoProcAmp->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1757 if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1758 pAMVideoProcAmp->Get(Property, &CurrVal, &CapsFlags);
1760 if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1762 if (useDefaultValue) {
1763 pAMVideoProcAmp->Set(Property, Default, VideoProcAmp_Flags_Auto);
1766 // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1767 pAMVideoProcAmp->Set(Property, lValue, Flags);
1770 if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1771 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1772 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1779 bool videoInput::setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags){
1780 if( !isDeviceSetup(deviceID) )return false;
1782 long min, max, currentValue, flags, defaultValue, stepAmnt;
1784 if( !getVideoSettingCamera(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1786 if(pctValue > 1.0)pctValue = 1.0;
1787 else if(pctValue < 0)pctValue = 0.0;
1789 float range = (float)max - (float)min;
1790 if(range <= 0)return false;
1791 if(stepAmnt == 0) return false;
1793 long value = (long)( (float)min + range * pctValue );
1794 long rasterValue = value;
1796 //if the range is the stepAmnt then it is just a switch
1797 //so we either set the value to low or high
1798 if( range == stepAmnt ){
1799 if( pctValue < 0.5)rasterValue = min;
1800 else rasterValue = max;
1802 //we need to rasterize the value to the stepping amnt
1803 long mod = value % stepAmnt;
1804 float halfStep = (float)stepAmnt * 0.5f;
1805 if( mod < halfStep ) rasterValue -= mod;
1806 else rasterValue += stepAmnt - mod;
1807 printf("RASTER - pctValue is %f - value is %li - step is %li - mod is %li - rasterValue is %li\n", pctValue, value, stepAmnt, mod, rasterValue);
1810 return setVideoSettingCamera(deviceID, Property, rasterValue, Flags, false);
1814 bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1815 IAMCameraControl *pIAMCameraControl;
1816 if(isDeviceSetup(deviceID))
1819 hr = getDevice(&VDList[deviceID]->pVideoInputFilter, deviceID, VDList[deviceID]->wDeviceName, VDList[deviceID]->nDeviceName);
1822 getCameraPropertyAsString(Property,propStr);
1824 if (verbose) printf("Setting video setting %s.\n", propStr);
1825 hr = VDList[deviceID]->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1832 long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags;
1833 pIAMCameraControl->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1834 if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1835 pIAMCameraControl->Get(Property, &CurrVal, &CapsFlags);
1836 if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1837 if (useDefaultValue) {
1838 pIAMCameraControl->Set(Property, Default, CameraControl_Flags_Auto);
1842 // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1843 pIAMCameraControl->Set(Property, lValue, Flags);
1845 pIAMCameraControl->Release();
1854 bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long ¤tValue, long &flags, long &defaultValue){
1855 if( !isDeviceSetup(deviceID) )return false;
1858 //bool isSuccessful = false;
1860 videoDevice * VD = VDList[deviceID];
1862 hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1864 printf("setVideoSetting - getDevice Error\n");
1868 IAMCameraControl *pIAMCameraControl = NULL;
1870 hr = VD->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1872 printf("setVideoSetting - QueryInterface Error\n");
1873 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1874 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1879 getCameraPropertyAsString(Property,propStr);
1880 if (verbose) printf("Setting video setting %s.\n", propStr);
1882 pIAMCameraControl->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1883 if (verbose) printf("Range for video setting %s: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", propStr, min, max, SteppingDelta, defaultValue, flags);
1884 pIAMCameraControl->Get(Property, ¤tValue, &flags);
1886 if(pIAMCameraControl)pIAMCameraControl->Release();
1887 if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1888 if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;
1895 // ----------------------------------------------------------------------
1896 // Shutsdown the device, deletes the object and creates a new object
1897 // so it is ready to be setup again
1898 // ----------------------------------------------------------------------
1900 void videoInput::stopDevice(int id){
1901 if(id < VI_MAX_CAMERAS)
1904 VDList[id] = new videoDevice();
1909 // ----------------------------------------------------------------------
1910 // Restarts the device with the same settings it was using
1912 // ----------------------------------------------------------------------
1914 bool videoInput::restartDevice(int id){
1915 if(isDeviceSetup(id))
1917 int conn = VDList[id]->storeConn;
1918 int tmpW = VDList[id]->width;
1919 int tmpH = VDList[id]->height;
1921 bool bFormat = VDList[id]->specificFormat;
1922 long format = VDList[id]->formatType;
1924 int nReconnect = VDList[id]->nFramesForReconnect;
1925 bool bReconnect = VDList[id]->autoReconnect;
1927 unsigned long avgFrameTime = VDList[id]->requestedFrameTime;
1931 //set our fps if needed
1932 if( avgFrameTime != (unsigned long)-1){
1933 VDList[id]->requestedFrameTime = avgFrameTime;
1936 if( setupDevice(id, tmpW, tmpH, conn) ){
1937 //reapply the format - ntsc / pal etc
1939 setFormat(id, format);
1942 setAutoReconnectOnFreeze(id, true, nReconnect);
1950 // ----------------------------------------------------------------------
1951 // Shuts down all devices, deletes objects and unitializes com if needed
1953 // ----------------------------------------------------------------------
1954 videoInput::~videoInput(){
1956 for(int i = 0; i < VI_MAX_CAMERAS; i++)
1965 ////////////////////////////// VIDEO INPUT ////////////////////////////////
1966 //////////////////////////// PRIVATE METHODS //////////////////////////////
1968 // ----------------------------------------------------------------------
1969 // We only should init com if it hasn't been done so by our apps thread
1970 // Use a static counter to keep track of other times it has been inited
1971 // (do we need to worry about multithreaded apps?)
1972 // ----------------------------------------------------------------------
1974 bool videoInput::comInit(){
1975 /*HRESULT hr = NOERROR;
1977 //no need for us to start com more than once
1978 if(comInitCount == 0 ){
1980 // Initialize the COM library.
1981 //CoInitializeEx so videoInput can run in another thread
1982 #ifdef VI_COM_MULTI_THREADED
1983 hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
1985 hr = CoInitialize(NULL);
1987 //this is the only case where there might be a problem
1988 //if another library has started com as single threaded
1989 //and we need it multi-threaded - send warning but don't fail
1990 if( hr == RPC_E_CHANGED_MODE){
1991 if(verbose)printf("SETUP - COM already setup - threaded VI might not be possible\n");
2000 // ----------------------------------------------------------------------
2001 // Same as above but to unitialize com, decreases counter and frees com
2002 // if no one else is using it
2003 // ----------------------------------------------------------------------
2005 bool videoInput::comUnInit(){
2006 /*if(comInitCount > 0)comInitCount--; //decrease the count of instances using com
2008 if(comInitCount == 0){
2009 CoUninitialize(); //if there are no instances left - uninitialize com
2018 // ----------------------------------------------------------------------
2019 // This is the size we ask for - we might not get it though :)
2021 // ----------------------------------------------------------------------
2023 void videoInput::setAttemptCaptureSize(int id, int w, int h,GUID mediaType){
2025 VDList[id]->tryWidth = w;
2026 VDList[id]->tryHeight = h;
2027 VDList[id]->tryDiffSize = true;
2028 VDList[id]->tryVideoType = mediaType;
2032 // ----------------------------------------------------------------------
2033 // Set the connection type
2034 // (maybe move to private?)
2035 // ----------------------------------------------------------------------
2037 void videoInput::setPhyCon(int id, int conn){
2042 VDList[id]->connection = PhysConn_Video_Composite;
2045 VDList[id]->connection = PhysConn_Video_SVideo;
2048 VDList[id]->connection = PhysConn_Video_Tuner;
2051 VDList[id]->connection = PhysConn_Video_USB;
2054 VDList[id]->connection = PhysConn_Video_1394;
2057 return; //if it is not these types don't set crossbar
2061 VDList[id]->storeConn = conn;
2062 VDList[id]->useCrossbar = true;
2066 // ----------------------------------------------------------------------
2067 // Check that we are not trying to setup a non-existant device
2068 // Then start the graph building!
2069 // ----------------------------------------------------------------------
2071 bool videoInput::setup(int deviceNumber){
2072 devicesFound = getDeviceCount();
2074 if(deviceNumber>devicesFound-1)
2076 if(verbose)printf("SETUP: device[%i] not found - you have %i devices available\n", deviceNumber, devicesFound);
2077 if(devicesFound>=0) if(verbose)printf("SETUP: this means that the last device you can use is device[%i] \n", devicesFound-1);
2081 if(VDList[deviceNumber]->readyToCapture)
2083 if(verbose)printf("SETUP: can't setup, device %i is currently being used\n",VDList[deviceNumber]->myID);
2087 HRESULT hr = start(deviceNumber, VDList[deviceNumber]);
2088 if(hr == S_OK)return true;
2093 // ----------------------------------------------------------------------
2094 // Does both vertical buffer flipping and bgr to rgb swapping
2095 // You have any combination of those.
2096 // ----------------------------------------------------------------------
2098 void videoInput::processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){
2100 int widthInBytes = width * 3;
2101 int numBytes = widthInBytes * height;
2109 for(int y = 0; y < height; y++){
2110 memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes);
2114 memcpy(dst, src, numBytes);
2120 int y = (height - 1) * widthInBytes;
2123 for(int i = 0; i < numBytes; i+=3){
2126 src -= widthInBytes*2;
2143 for(int i = 0; i < numBytes; i+=3){
2160 //------------------------------------------------------------------------------------------
2161 void videoInput::getMediaSubtypeAsString(GUID type, char * typeAsString){
2164 if( type == MEDIASUBTYPE_RGB24) sprintf(tmpStr, "RGB24");
2165 else if(type == MEDIASUBTYPE_RGB32) sprintf(tmpStr, "RGB32");
2166 else if(type == MEDIASUBTYPE_RGB555)sprintf(tmpStr, "RGB555");
2167 else if(type == MEDIASUBTYPE_RGB565)sprintf(tmpStr, "RGB565");
2168 else if(type == MEDIASUBTYPE_YUY2) sprintf(tmpStr, "YUY2");
2169 else if(type == MEDIASUBTYPE_YVYU) sprintf(tmpStr, "YVYU");
2170 else if(type == MEDIASUBTYPE_YUYV) sprintf(tmpStr, "YUYV");
2171 else if(type == MEDIASUBTYPE_IYUV) sprintf(tmpStr, "IYUV");
2172 else if(type == MEDIASUBTYPE_UYVY) sprintf(tmpStr, "UYVY");
2173 else if(type == MEDIASUBTYPE_YV12) sprintf(tmpStr, "YV12");
2174 else if(type == MEDIASUBTYPE_YVU9) sprintf(tmpStr, "YVU9");
2175 else if(type == MEDIASUBTYPE_Y411) sprintf(tmpStr, "Y411");
2176 else if(type == MEDIASUBTYPE_Y41P) sprintf(tmpStr, "Y41P");
2177 else if(type == MEDIASUBTYPE_Y211) sprintf(tmpStr, "Y211");
2178 else if(type == MEDIASUBTYPE_AYUV) sprintf(tmpStr, "AYUV");
2179 else if(type == MEDIASUBTYPE_MJPG) sprintf(tmpStr, "MJPG");
2180 else if(type == MEDIASUBTYPE_Y800) sprintf(tmpStr, "Y800");
2181 else if(type == MEDIASUBTYPE_Y8) sprintf(tmpStr, "Y8");
2182 else if(type == MEDIASUBTYPE_GREY) sprintf(tmpStr, "GREY");
2183 else if(type == MEDIASUBTYPE_I420) sprintf(tmpStr, "I420");
2184 else sprintf(tmpStr, "OTHER");
2186 memcpy(typeAsString, tmpStr, sizeof(char)*8);
2189 int videoInput::getFourccFromMediaSubtype(GUID type) {
2193 GUID *videoInput::getMediaSubtypeFromFourcc(int fourcc){
2195 for (int i=0;i<VI_NUM_TYPES;i++) {
2196 if ( (unsigned long)(unsigned)fourcc == mediaSubtypes[i].Data1 ) {
2197 return &mediaSubtypes[i];
2205 void videoInput::getVideoPropertyAsString(int prop, char * propertyAsString){
2209 if ( prop==VideoProcAmp_Brightness) sprintf(tmpStr, "Brightness");
2210 else if ( prop==VideoProcAmp_Contrast) sprintf(tmpStr, "Contrast");
2211 else if ( prop==VideoProcAmp_Saturation) sprintf(tmpStr, "Saturation");
2212 else if ( prop==VideoProcAmp_Hue) sprintf(tmpStr, "Hue");
2213 else if ( prop==VideoProcAmp_Gain) sprintf(tmpStr, "Gain");
2214 else if ( prop==VideoProcAmp_Gamma) sprintf(tmpStr, "Gamma");
2215 else if ( prop==VideoProcAmp_ColorEnable) sprintf(tmpStr, "ColorEnable");
2216 else if ( prop==VideoProcAmp_Sharpness) sprintf(tmpStr, "Sharpness");
2217 else sprintf(tmpStr, "%u",prop);
2219 memcpy(propertyAsString, tmpStr, sizeof(char)*16);
2223 int videoInput::getVideoPropertyFromCV(int cv_property){
2225 // see VideoProcAmpProperty in strmif.h
2226 switch (cv_property) {
2227 case CV_CAP_PROP_BRIGHTNESS:
2228 return VideoProcAmp_Brightness;
2230 case CV_CAP_PROP_CONTRAST:
2231 return VideoProcAmp_Contrast;
2233 case CV_CAP_PROP_HUE:
2234 return VideoProcAmp_Hue;
2236 case CV_CAP_PROP_SATURATION:
2237 return VideoProcAmp_Saturation;
2239 case CV_CAP_PROP_SHARPNESS:
2240 return VideoProcAmp_Sharpness;
2242 case CV_CAP_PROP_GAMMA:
2243 return VideoProcAmp_Gamma;
2245 case CV_CAP_PROP_MONOCROME:
2246 return VideoProcAmp_ColorEnable;
2248 case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
2249 return VideoProcAmp_WhiteBalance;
2251 case CV_CAP_PROP_BACKLIGHT:
2252 return VideoProcAmp_BacklightCompensation;
2254 case CV_CAP_PROP_GAIN:
2255 return VideoProcAmp_Gain;
2260 int videoInput::getCameraPropertyFromCV(int cv_property){
2262 // see CameraControlProperty in strmif.h
2263 switch (cv_property) {
2264 case CV_CAP_PROP_PAN:
2265 return CameraControl_Pan;
2267 case CV_CAP_PROP_TILT:
2268 return CameraControl_Tilt;
2270 case CV_CAP_PROP_ROLL:
2271 return CameraControl_Roll;
2273 case CV_CAP_PROP_ZOOM:
2274 return CameraControl_Zoom;
2276 case CV_CAP_PROP_EXPOSURE:
2277 return CameraControl_Exposure;
2279 case CV_CAP_PROP_IRIS:
2280 return CameraControl_Iris;
2282 case CV_CAP_PROP_FOCUS:
2283 return CameraControl_Focus;
2288 void videoInput::getCameraPropertyAsString(int prop, char * propertyAsString){
2292 if ( prop==CameraControl_Pan) sprintf(tmpStr, "Pan");
2293 else if ( prop==CameraControl_Tilt) sprintf(tmpStr, "Tilt");
2294 else if ( prop==CameraControl_Roll) sprintf(tmpStr, "Roll");
2295 else if ( prop==CameraControl_Zoom) sprintf(tmpStr, "Zoom");
2296 else if ( prop==CameraControl_Exposure) sprintf(tmpStr, "Exposure");
2297 else if ( prop==CameraControl_Iris) sprintf(tmpStr, "Iris");
2298 else if ( prop==CameraControl_Focus) sprintf(tmpStr, "Focus");
2299 else sprintf(tmpStr, "%u",prop);
2301 memcpy(propertyAsString, tmpStr, sizeof(char)*16);
2305 //-------------------------------------------------------------------------------------------
2306 static void findClosestSizeAndSubtype(videoDevice * VD, int widthIn, int heightIn, int &widthOut, int &heightOut, GUID & mediatypeOut){
2309 //find perfect match or closest size
2310 int nearW = 9999999;
2311 int nearH = 9999999;
2312 //bool foundClosestMatch = true;
2316 hr = VD->streamConf->GetNumberOfCapabilities(&iCount, &iSize);
2318 if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
2320 //For each format type RGB24 YUV2 etc
2321 for (int iFormat = 0; iFormat < iCount; iFormat++)
2323 VIDEO_STREAM_CONFIG_CAPS scc;
2324 AM_MEDIA_TYPE *pmtConfig;
2325 hr = VD->streamConf->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
2329 //his is how many diff sizes are available for the format
2330 int stepX = scc.OutputGranularityX;
2331 int stepY = scc.OutputGranularityY;
2336 //Don't want to get stuck in a loop
2337 if(stepX < 1 || stepY < 1) continue;
2339 //if(verbose)printf("min is %i %i max is %i %i - res is %i %i \n", scc.MinOutputSize.cx, scc.MinOutputSize.cy, scc.MaxOutputSize.cx, scc.MaxOutputSize.cy, stepX, stepY);
2340 //if(verbose)printf("min frame duration is %i max duration is %i\n", scc.MinFrameInterval, scc.MaxFrameInterval);
2342 bool exactMatch = false;
2343 bool exactMatchX = false;
2344 bool exactMatchY = false;
2346 for(int x = scc.MinOutputSize.cx; x <= scc.MaxOutputSize.cx; x+= stepX){
2347 //If we find an exact match
2352 //Otherwise lets find the closest match based on width
2353 else if( abs(widthIn-x) < abs(widthIn-tempW) ){
2358 for(int y = scc.MinOutputSize.cy; y <= scc.MaxOutputSize.cy; y+= stepY){
2359 //If we find an exact match
2364 //Otherwise lets find the closest match based on height
2365 else if( abs(heightIn-y) < abs(heightIn-tempH) ){
2370 //see if we have an exact match!
2371 if(exactMatchX && exactMatchY){
2372 //foundClosestMatch = false;
2376 heightOut = heightIn;
2377 mediatypeOut = pmtConfig->subtype;
2380 //otherwise lets see if this filters closest size is the closest
2381 //available. the closest size is determined by the sum difference
2382 //of the widths and heights
2383 else if( abs(widthIn - tempW) + abs(heightIn - tempH) < abs(widthIn - nearW) + abs(heightIn - nearH) )
2390 mediatypeOut = pmtConfig->subtype;
2393 MyDeleteMediaType(pmtConfig);
2395 //If we have found an exact match no need to search anymore
2396 if(exactMatch)break;
2404 //---------------------------------------------------------------------------------------------------
2405 static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHeight, GUID mediatype){
2406 VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
2408 //store current size
2409 //int tmpWidth = HEADER(pVih)->biWidth;
2410 //int tmpHeight = HEADER(pVih)->biHeight;
2411 AM_MEDIA_TYPE * tmpType = NULL;
2413 HRESULT hr = VD->streamConf->GetFormat(&tmpType);
2414 if(hr != S_OK)return false;
2418 HEADER(pVih)->biWidth = attemptWidth;
2419 HEADER(pVih)->biHeight = attemptHeight;
2421 VD->pAmMediaType->formattype = FORMAT_VideoInfo;
2422 VD->pAmMediaType->majortype = MEDIATYPE_Video;
2423 VD->pAmMediaType->subtype = mediatype;
2426 VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight*3;
2428 //set fps if requested
2429 if( VD->requestedFrameTime != -1){
2430 pVih->AvgTimePerFrame = VD->requestedFrameTime;
2433 //okay lets try new size
2434 hr = VD->streamConf->SetFormat(VD->pAmMediaType);
2436 if( tmpType != NULL )MyDeleteMediaType(tmpType);
2439 VD->streamConf->SetFormat(tmpType);
2440 if( tmpType != NULL )MyDeleteMediaType(tmpType);
2446 // ----------------------------------------------------------------------
2447 // Where all the work happens!
2448 // Attempts to build a graph for the specified device
2449 // ----------------------------------------------------------------------
2451 int videoInput::start(int deviceID, videoDevice *VD){
2453 HRESULT hr = NOERROR;
2454 VD->myID = deviceID;
2455 VD->setupStarted = true;
2456 CAPTURE_MODE = PIN_CATEGORY_CAPTURE; //Don't worry - it ends up being preview (which is faster)
2457 callbackSetCount = 1; //make sure callback method is not changed after setup called
2459 if(verbose)printf("SETUP: Setting up device %i\n",deviceID);
2461 // CREATE THE GRAPH BUILDER //
2462 // Create the filter graph manager and query for interfaces.
2463 hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&VD->pCaptureGraph);
2464 if (FAILED(hr)) // FAILED is a macro that tests the return value
2466 if(verbose)printf("ERROR - Could not create the Filter Graph Manager\n");
2470 //FITLER GRAPH MANAGER//
2471 // Create the Filter Graph Manager.
2472 hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&VD->pGraph);
2475 if(verbose)printf("ERROR - Could not add the graph builder!\n");
2476 stopDevice(deviceID);
2480 //SET THE FILTERGRAPH//
2481 hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph);
2484 if(verbose)printf("ERROR - Could not set filtergraph\n");
2485 stopDevice(deviceID);
2489 //MEDIA CONTROL (START/STOPS STREAM)//
2490 // Using QueryInterface on the graph builder,
2491 // Get the Media Control object.
2492 hr = VD->pGraph->QueryInterface(IID_IMediaControl, (void **)&VD->pControl);
2495 if(verbose)printf("ERROR - Could not create the Media Control object\n");
2496 stopDevice(deviceID);
2501 //FIND VIDEO DEVICE AND ADD TO GRAPH//
2502 //gets the device specified by the second argument.
2503 hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
2506 if(verbose)printf("SETUP: %s\n", VD->nDeviceName);
2507 hr = VD->pGraph->AddFilter(VD->pVideoInputFilter, VD->wDeviceName);
2509 if(verbose)printf("ERROR - Could not find specified video device\n");
2510 stopDevice(deviceID);
2514 //LOOK FOR PREVIEW PIN IF THERE IS NONE THEN WE USE CAPTURE PIN AND THEN SMART TEE TO PREVIEW
2515 IAMStreamConfig *streamConfTest = NULL;
2516 hr = VD->pCaptureGraph->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&streamConfTest);
2518 if(verbose)printf("SETUP: Couldn't find preview pin using SmartTee\n");
2520 CAPTURE_MODE = PIN_CATEGORY_PREVIEW;
2521 streamConfTest->Release();
2522 streamConfTest = NULL;
2525 //CROSSBAR (SELECT PHYSICAL INPUT TYPE)//
2526 //my own function that checks to see if the device can support a crossbar and if so it routes it.
2527 //webcams tend not to have a crossbar so this function will also detect a webcams and not apply the crossbar
2530 if(verbose)printf("SETUP: Checking crossbar\n");
2531 routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE);
2535 //we do this because webcams don't have a preview mode
2536 hr = VD->pCaptureGraph->FindInterface(&CAPTURE_MODE, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&VD->streamConf);
2538 if(verbose)printf("ERROR: Couldn't config the stream!\n");
2539 stopDevice(deviceID);
2543 //NOW LETS DEAL WITH GETTING THE RIGHT SIZE
2544 hr = VD->streamConf->GetFormat(&VD->pAmMediaType);
2546 if(verbose)printf("ERROR: Couldn't getFormat for pAmMediaType!\n");
2547 stopDevice(deviceID);
2551 VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
2552 int currentWidth = HEADER(pVih)->biWidth;
2553 int currentHeight = HEADER(pVih)->biHeight;
2555 bool customSize = VD->tryDiffSize;
2557 bool foundSize = false;
2560 if(verbose) printf("SETUP: Default Format is set to %i by %i \n", currentWidth, currentHeight);
2563 // try specified format and size
2564 getMediaSubtypeAsString(VD->tryVideoType, guidStr);
2565 if(verbose)printf("SETUP: trying specified format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight);
2567 if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, VD->tryVideoType) ){
2568 VD->setSize(VD->tryWidth, VD->tryHeight);
2571 // try specified size with all formats
2572 for(int i = 0; i < VI_NUM_TYPES; i++){
2574 getMediaSubtypeAsString(mediaSubtypes[i], guidStr);
2576 if(verbose)printf("SETUP: trying format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight);
2577 if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){
2578 VD->setSize(VD->tryWidth, VD->tryHeight);
2586 //if we didn't find the requested size - lets try and find the closest matching size
2587 if( foundSize == false ){
2588 if( verbose )printf("SETUP: couldn't find requested size - searching for closest matching size\n");
2590 int closestWidth = -1;
2591 int closestHeight = -1;
2592 GUID newMediaSubtype;
2594 findClosestSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, closestWidth, closestHeight, newMediaSubtype);
2596 if( closestWidth != -1 && closestHeight != -1){
2597 getMediaSubtypeAsString(newMediaSubtype, guidStr);
2599 if(verbose)printf("SETUP: closest supported size is %s @ %i %i\n", guidStr, closestWidth, closestHeight);
2600 if( setSizeAndSubtype(VD, closestWidth, closestHeight, newMediaSubtype) ){
2601 VD->setSize(closestWidth, closestHeight);
2608 //if we didn't specify a custom size or if we did but couldn't find it lets setup with the default settings
2609 if(customSize == false || foundSize == false){
2610 if( VD->requestedFrameTime != -1 ){
2611 pVih->AvgTimePerFrame = VD->requestedFrameTime;
2612 hr = VD->streamConf->SetFormat(VD->pAmMediaType);
2614 VD->setSize(currentWidth, currentHeight);
2617 //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
2618 // Create the Sample Grabber.
2619 hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&VD->pGrabberF);
2621 if(verbose)printf("Could not Create Sample Grabber - CoCreateInstance()\n");
2622 stopDevice(deviceID);
2626 hr = VD->pGraph->AddFilter(VD->pGrabberF, L"Sample Grabber");
2628 if(verbose)printf("Could not add Sample Grabber - AddFilter()\n");
2629 stopDevice(deviceID);
2633 hr = VD->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&VD->pGrabber);
2635 if(verbose)printf("ERROR: Could not query SampleGrabber\n");
2636 stopDevice(deviceID);
2641 //Set Params - One Shot should be false unless you want to capture just one buffer
2642 hr = VD->pGrabber->SetOneShot(FALSE);
2644 hr = VD->pGrabber->SetBufferSamples(FALSE);
2646 hr = VD->pGrabber->SetBufferSamples(TRUE);
2650 //Tell the grabber to use our callback function - 0 is for SampleCB and 1 for BufferCB
2652 hr = VD->pGrabber->SetCallback(VD->sgCallback, 0);
2654 if(verbose)printf("ERROR: problem setting callback\n");
2655 stopDevice(deviceID);
2658 if(verbose)printf("SETUP: Capture callback set\n");
2663 //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image)
2664 //zero the media type - lets try this :) - maybe this works?
2666 ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
2668 mt.majortype = MEDIATYPE_Video;
2669 mt.subtype = MEDIASUBTYPE_RGB24;
2670 mt.formattype = FORMAT_VideoInfo;
2672 //VD->pAmMediaType->subtype = VD->videoType;
2673 hr = VD->pGrabber->SetMediaType(&mt);
2675 //lets try freeing our stream conf here too
2676 //this will fail if the device is already running
2678 VD->streamConf->Release();
2679 VD->streamConf = NULL;
2681 if(verbose)printf("ERROR: connecting device - prehaps it is already being used?\n");
2682 stopDevice(deviceID);
2688 //used to give the video stream somewhere to go to.
2689 hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&VD->pDestFilter));
2691 if(verbose)printf("ERROR: Could not create filter - NullRenderer\n");
2692 stopDevice(deviceID);
2696 hr = VD->pGraph->AddFilter(VD->pDestFilter, L"NullRenderer");
2698 if(verbose)printf("ERROR: Could not add filter - NullRenderer\n");
2699 stopDevice(deviceID);
2704 //This is where the stream gets put together.
2705 hr = VD->pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, VD->pGrabberF, VD->pDestFilter);
2708 if(verbose)printf("ERROR: Could not connect pins - RenderStream()\n");
2709 stopDevice(deviceID);
2714 //EXP - lets try setting the sync source to null - and make it run as fast as possible
2716 IMediaFilter *pMediaFilter = 0;
2717 hr = VD->pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
2719 if(verbose)printf("ERROR: Could not get IID_IMediaFilter interface\n");
2721 pMediaFilter->SetSyncSource(NULL);
2722 pMediaFilter->Release();
2727 //LETS RUN THE STREAM!
2728 hr = VD->pControl->Run();
2731 if(verbose)printf("ERROR: Could not start graph\n");
2732 stopDevice(deviceID);
2737 //MAKE SURE THE DEVICE IS SENDING VIDEO BEFORE WE FINISH
2740 long bufferSize = VD->videoSize;
2743 hr = VD->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VD->pBuffer);
2749 if(verbose)printf("SETUP: Device is setup and ready to capture.\n\n");
2750 VD->readyToCapture = true;
2752 //Release filters - seen someone else do this
2753 //looks like it solved the freezes
2755 //if we release this then we don't have access to the settings
2756 //we release our video input filter but then reconnect with it
2757 //each time we need to use it
2758 VD->pVideoInputFilter->Release();
2759 VD->pVideoInputFilter = NULL;
2761 VD->pGrabberF->Release();
2762 VD->pGrabberF = NULL;
2764 VD->pDestFilter->Release();
2765 VD->pDestFilter = NULL;
2771 // ----------------------------------------------------------------------
2772 // Returns number of good devices
2774 // ----------------------------------------------------------------------
2776 int videoInput::getDeviceCount(){
2779 ICreateDevEnum *pDevEnum = NULL;
2780 IEnumMoniker *pEnum = NULL;
2781 int deviceCounter = 0;
2783 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
2784 CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
2785 reinterpret_cast<void**>(&pDevEnum));
2790 // Create an enumerator for the video capture category.
2791 hr = pDevEnum->CreateClassEnumerator(
2792 CLSID_VideoInputDeviceCategory,
2796 IMoniker *pMoniker = NULL;
2797 while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
2799 IPropertyBag *pPropBag;
2800 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag,
2801 (void**)(&pPropBag));
2804 pMoniker->Release();
2805 continue; // Skip this one, maybe the next one will work.
2808 pPropBag->Release();
2811 pMoniker->Release();
2821 pDevEnum->Release();
2824 return deviceCounter;
2828 // ----------------------------------------------------------------------
2831 // Enumerate all of the video input devices
2832 // Return the filter with a matching friendly name
2833 // ----------------------------------------------------------------------
2835 HRESULT videoInput::getDevice(IBaseFilter** gottaFilter, int deviceId, WCHAR * wDeviceName, char * nDeviceName){
2837 int deviceCounter = 0;
2839 // Create the System Device Enumerator.
2840 ICreateDevEnum *pSysDevEnum = NULL;
2841 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
2847 // Obtain a class enumerator for the video input category.
2848 IEnumMoniker *pEnumCat = NULL;
2849 hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
2853 // Enumerate the monikers.
2854 IMoniker *pMoniker = NULL;
2856 while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done))
2858 if(deviceCounter == deviceId)
2860 // Bind the first moniker to an object
2861 IPropertyBag *pPropBag;
2862 hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
2865 // To retrieve the filter's friendly name, do the following:
2867 VariantInit(&varName);
2868 hr = pPropBag->Read(L"FriendlyName", &varName, 0);
2872 //copy the name to nDeviceName & wDeviceName
2874 while( varName.bstrVal[count] != 0x00 ) {
2875 wDeviceName[count] = varName.bstrVal[count];
2876 nDeviceName[count] = (char)varName.bstrVal[count];
2880 // We found it, so send it back to the caller
2881 hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter);
2884 VariantClear(&varName);
2885 pPropBag->Release();
2887 pMoniker->Release();
2893 pEnumCat->Release();
2896 pSysDevEnum->Release();
2900 return hr; // found it, return native error
2902 return VFW_E_NOT_FOUND; // didn't find it error
2907 // ----------------------------------------------------------------------
2908 // Show the property pages for a filter
2909 // This is stolen from the DX9 SDK
2910 // ----------------------------------------------------------------------
2912 HRESULT videoInput::ShowFilterPropertyPages(IBaseFilter *pFilter){
2914 ISpecifyPropertyPages *pProp;
2916 HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
2919 // Get the filter's name and IUnknown pointer.
2920 FILTER_INFO FilterInfo;
2921 hr = pFilter->QueryFilterInfo(&FilterInfo);
2922 IUnknown *pFilterUnk;
2923 pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);
2927 pProp->GetPages(&caGUID);
2929 OleCreatePropertyFrame(
2930 NULL, // Parent window
2932 FilterInfo.achName, // Caption for the dialog box
2933 1, // Number of objects (just the filter)
2934 &pFilterUnk, // Array of object pointers.
2935 caGUID.cElems, // Number of property pages
2936 caGUID.pElems, // Array of property page CLSIDs
2937 0, // Locale identifier
2942 if(pFilterUnk)pFilterUnk->Release();
2943 if(FilterInfo.pGraph)FilterInfo.pGraph->Release();
2944 CoTaskMemFree(caGUID.pElems);
2949 HRESULT videoInput::ShowStreamPropertyPages(IAMStreamConfig * /*pStream*/){
2951 HRESULT hr = NOERROR;
2955 // ----------------------------------------------------------------------
2956 // This code was also brazenly stolen from the DX9 SDK
2957 // Pass it a file name in wszPath, and it will save the filter graph to that file.
2958 // ----------------------------------------------------------------------
2960 HRESULT videoInput::SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) {
2961 const WCHAR wszStreamName[] = L"ActiveMovieGraph";
2963 IStorage *pStorage = NULL;
2965 // First, create a document file which will hold the GRF file
2966 hr = StgCreateDocfile(
2968 STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
2975 // Next, create a stream to store.
2977 hr = pStorage->CreateStream(
2979 STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
2983 pStorage->Release();
2987 // The IPersistStream converts a stream into a persistent object.
2988 IPersistStream *pPersist = NULL;
2989 pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast<void**>(&pPersist));
2990 hr = pPersist->Save(pStream, TRUE);
2992 pPersist->Release();
2995 hr = pStorage->Commit(STGC_DEFAULT);
2997 pStorage->Release();
3002 // ----------------------------------------------------------------------
3003 // For changing the input types
3005 // ----------------------------------------------------------------------
3007 HRESULT videoInput::routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode){
3009 //create local ICaptureGraphBuilder2
3010 ICaptureGraphBuilder2 *pBuild = NULL;
3013 //create local IBaseFilter
3014 IBaseFilter *pVidFilter = NULL;
3015 pVidFilter = * pVidInFilter;
3017 // Search upstream for a crossbar.
3018 IAMCrossbar *pXBar1 = NULL;
3019 HRESULT hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pVidFilter,
3020 IID_IAMCrossbar, (void**)&pXBar1);
3024 bool foundDevice = false;
3026 if(verbose)printf("SETUP: You are not a webcam! Setting Crossbar\n");
3029 IAMCrossbar *Crossbar;
3030 hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Interleaved, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
3033 hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Video, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
3036 LONG lInpin, lOutpin;
3037 hr = Crossbar->get_PinCounts(&lOutpin , &lInpin);
3039 BOOL iPin=TRUE; LONG pIndex=0 , pRIndex=0 , pType=0;
3041 while( pIndex < lInpin)
3043 hr = Crossbar->get_CrossbarPinInfo( iPin , pIndex , &pRIndex , &pType);
3045 if( pType == conType){
3046 if(verbose)printf("SETUP: Found Physical Interface");
3050 case PhysConn_Video_Composite:
3051 if(verbose)printf(" - Composite\n");
3053 case PhysConn_Video_SVideo:
3054 if(verbose)printf(" - S-Video\n");
3056 case PhysConn_Video_Tuner:
3057 if(verbose)printf(" - Tuner\n");
3059 case PhysConn_Video_USB:
3060 if(verbose)printf(" - USB\n");
3062 case PhysConn_Video_1394:
3063 if(verbose)printf(" - Firewire\n");
3075 BOOL OPin=FALSE; LONG pOIndex=0 , pORIndex=0 , pOType=0;
3076 while( pOIndex < lOutpin)
3078 hr = Crossbar->get_CrossbarPinInfo( OPin , pOIndex , &pORIndex , &pOType);
3079 if( pOType == PhysConn_Video_VideoDecoder)
3082 Crossbar->Route(pOIndex,pIndex);
3084 if(verbose) printf("SETUP: Didn't find specified Physical Connection type. Using Defualt. \n");
3087 //we only free the crossbar when we close or restart the device
3088 //we were getting a crash otherwise
3089 //if(Crossbar)Crossbar->Release();
3090 //if(Crossbar)Crossbar = NULL;
3092 if(pXBar1)pXBar1->Release();
3093 if(pXBar1)pXBar1 = NULL;
3096 if(verbose) printf("SETUP: You are a webcam or snazzy firewire cam! No Crossbar needed\n");
3104 /********************* Capturing video from camera via DirectShow *********************/
3106 class CvCaptureCAM_DShow : public CvCapture
3109 CvCaptureCAM_DShow();
3110 virtual ~CvCaptureCAM_DShow();
3112 virtual bool open( int index );
3113 virtual void close();
3114 virtual double getProperty(int);
3115 virtual bool setProperty(int, double);
3116 virtual bool grabFrame();
3117 virtual IplImage* retrieveFrame(int);
3118 virtual int getCaptureDomain() { return CV_CAP_DSHOW; } // Return the type of the capture object: CV_CAP_VFW, etc...
3123 int index, width, height,fourcc;
3124 int widthSet, heightSet;
3126 static videoInput VI;
3130 struct SuppressVideoInputMessages
3132 SuppressVideoInputMessages() { videoInput::setVerbose(false); }
3135 static SuppressVideoInputMessages do_it;
3136 videoInput CvCaptureCAM_DShow::VI;
3138 CvCaptureCAM_DShow::CvCaptureCAM_DShow()
3142 width = height = fourcc = -1;
3143 widthSet = heightSet = -1;
3147 CvCaptureCAM_DShow::~CvCaptureCAM_DShow()
3153 void CvCaptureCAM_DShow::close()
3157 VI.stopDevice(index);
3159 cvReleaseImage(&frame);
3161 widthSet = heightSet = width = height = -1;
3164 // Initialize camera input
3165 bool CvCaptureCAM_DShow::open( int _index )
3170 devices = VI.listDevices(true);
3173 if (_index < 0 || _index > devices-1)
3175 VI.setupDevice(_index);
3176 if( !VI.isDeviceSetup(_index) )
3182 bool CvCaptureCAM_DShow::grabFrame()
3188 IplImage* CvCaptureCAM_DShow::retrieveFrame(int)
3190 if( !frame || VI.getWidth(index) != frame->width || VI.getHeight(index) != frame->height )
3193 cvReleaseImage( &frame );
3194 int w = VI.getWidth(index), h = VI.getHeight(index);
3195 frame = cvCreateImage( cvSize(w,h), 8, 3 );
3198 if (VI.getPixels( index, (uchar*)frame->imageData, false, true ))
3204 double CvCaptureCAM_DShow::getProperty( int property_id )
3207 long min_value,max_value,stepping_delta,current_value,flags,defaultValue;
3209 // image format proprrties
3210 switch( property_id )
3212 case CV_CAP_PROP_FRAME_WIDTH:
3213 return VI.getWidth(index);
3215 case CV_CAP_PROP_FRAME_HEIGHT:
3216 return VI.getHeight(index);
3218 case CV_CAP_PROP_FOURCC:
3219 return VI.getFourcc(index);
3221 case CV_CAP_PROP_FPS:
3222 return VI.getFPS(index);
3225 // video filter properties
3226 switch( property_id )
3228 case CV_CAP_PROP_BRIGHTNESS:
3229 case CV_CAP_PROP_CONTRAST:
3230 case CV_CAP_PROP_HUE:
3231 case CV_CAP_PROP_SATURATION:
3232 case CV_CAP_PROP_SHARPNESS:
3233 case CV_CAP_PROP_GAMMA:
3234 case CV_CAP_PROP_MONOCROME:
3235 case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
3236 case CV_CAP_PROP_BACKLIGHT:
3237 case CV_CAP_PROP_GAIN:
3238 if (VI.getVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value;
3241 // camera properties
3242 switch( property_id )
3244 case CV_CAP_PROP_PAN:
3245 case CV_CAP_PROP_TILT:
3246 case CV_CAP_PROP_ROLL:
3247 case CV_CAP_PROP_ZOOM:
3248 case CV_CAP_PROP_EXPOSURE:
3249 case CV_CAP_PROP_IRIS:
3250 case CV_CAP_PROP_FOCUS:
3251 if (VI.getVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),min_value,max_value,stepping_delta,current_value,flags,defaultValue) ) return (double)current_value;
3255 // unknown parameter or value not available
3259 bool CvCaptureCAM_DShow::setProperty( int property_id, double value )
3261 // image capture properties
3262 bool handled = false;
3263 switch( property_id )
3265 case CV_CAP_PROP_FRAME_WIDTH:
3266 width = cvRound(value);
3270 case CV_CAP_PROP_FRAME_HEIGHT:
3271 height = cvRound(value);
3275 case CV_CAP_PROP_FOURCC:
3276 fourcc = (int)(unsigned long)(value);
3277 if ( fourcc == -1 ) {
3278 // following cvCreateVideo usage will pop up caprturepindialog here if fourcc=-1
3279 // TODO - how to create a capture pin dialog
3284 case CV_CAP_PROP_FPS:
3285 int fps = cvRound(value);
3286 if (fps != VI.getFPS(index))
3288 VI.stopDevice(index);
3289 VI.setIdealFramerate(index,fps);
3290 if (widthSet > 0 && heightSet > 0)
3291 VI.setupDevice(index, widthSet, heightSet);
3293 VI.setupDevice(index);
3295 return VI.isDeviceSetup(index);
3301 if( width > 0 && height > 0 )
3303 if( width != VI.getWidth(index) || height != VI.getHeight(index) )//|| fourcc != VI.getFourcc(index) )
3305 int fps = static_cast<int>(VI.getFPS(index));
3306 VI.stopDevice(index);
3307 VI.setIdealFramerate(index, fps);
3308 VI.setupDeviceFourcc(index, width, height, fourcc);
3311 bool success = VI.isDeviceSetup(index);
3316 width = height = fourcc = -1;
3323 // show video/camera filter dialog
3324 if ( property_id == CV_CAP_PROP_SETTINGS ) {
3325 VI.showSettingsWindow(index);
3329 //video Filter properties
3330 switch( property_id )
3332 case CV_CAP_PROP_BRIGHTNESS:
3333 case CV_CAP_PROP_CONTRAST:
3334 case CV_CAP_PROP_HUE:
3335 case CV_CAP_PROP_SATURATION:
3336 case CV_CAP_PROP_SHARPNESS:
3337 case CV_CAP_PROP_GAMMA:
3338 case CV_CAP_PROP_MONOCROME:
3339 case CV_CAP_PROP_WHITE_BALANCE_BLUE_U:
3340 case CV_CAP_PROP_BACKLIGHT:
3341 case CV_CAP_PROP_GAIN:
3342 return VI.setVideoSettingFilter(index,VI.getVideoPropertyFromCV(property_id),(long)value);
3346 switch( property_id )
3348 case CV_CAP_PROP_PAN:
3349 case CV_CAP_PROP_TILT:
3350 case CV_CAP_PROP_ROLL:
3351 case CV_CAP_PROP_ZOOM:
3352 case CV_CAP_PROP_EXPOSURE:
3353 case CV_CAP_PROP_IRIS:
3354 case CV_CAP_PROP_FOCUS:
3355 return VI.setVideoSettingCamera(index,VI.getCameraPropertyFromCV(property_id),(long)value);
3362 CvCapture* cvCreateCameraCapture_DShow( int index )
3364 CvCaptureCAM_DShow* capture = new CvCaptureCAM_DShow;
3368 if( capture->open( index ))