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