source: eviacam/trunk/fuentes/creavision/videoInput.cpp @ 567

Last change on this file since 567 was 567, checked in by mabarracus, 4 years ago

updated sources to version 2.0.3

  • Property svn:executable set to *
File size: 72.3 KB
Line 
1// Modified by Cmauri 2010-03-31. See showSettingsWindow
2
3//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
4//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
5//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
6//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
7//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
8//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
9//THE SOFTWARE.
10
11//#define DEBUG 1
12//#define _DEBUG 1
13
14#include "videoInput.h"
15#include "tchar.h"
16
17/*
18        If you get errors when including Microsoft DirectShow or DirectDraw headers, the following message from Peter Whaite could help:
19
20        > This causes compilation errors within DirectShow:
21        >
22        > wxutil.h(125) : error C2065: 'EXECUTE_ASSERT' : undeclared identifier
23        > amfilter.h(1099) : error C2065: 'ASSERT' : undeclared identifier
24
25        The reason for this is that __WXDEBUG__ is also used by the DXSDK (9.0
26        in my case) to '#pragma once' the contents of
27        DXSDK/Samples/C++/DirectShow/BaseClasses/wxdebug.h.  So if __WXDEBUG__
28        is defined, then wxdebug.h doesn't get included, and the assert macros
29        don't get defined.  You have to #undef __WXDEBUG__ before including the
30        directshow baseclass's <streams.h>
31*/
32#undef __WXDEBUG__
33
34//Include Directshow stuff here so we don't worry about needing all the h files.
35#include "DShow.h"
36#include "streams.h"
37#include "qedit.h"
38#include "vector"
39#include "Aviriff.h"
40#include "Windows.h"
41
42//for threading
43#include <process.h>
44
45CFactoryTemplate * g_Templates;
46int g_cTemplates= 0;
47
48
49///////////////////////////  HANDY FUNCTIONS  /////////////////////////////
50
51void MyFreeMediaType(AM_MEDIA_TYPE& mt){
52    if (mt.cbFormat != 0)
53    {
54        CoTaskMemFree((PVOID)mt.pbFormat);
55        mt.cbFormat = 0;
56        mt.pbFormat = NULL;
57    }
58    if (mt.pUnk != NULL)
59    {
60        // Unecessary because pUnk should not be used, but safest.
61        mt.pUnk->Release();
62        mt.pUnk = NULL;
63    }
64}
65
66void MyDeleteMediaType(AM_MEDIA_TYPE *pmt)
67{
68    if (pmt != NULL)
69    {
70        MyFreeMediaType(*pmt); 
71        CoTaskMemFree(pmt);
72    }
73}
74
75//////////////////////////////  CALLBACK  ////////////////////////////////
76
77//Callback class
78class SampleGrabberCallback : public ISampleGrabberCB{
79public:
80
81        //------------------------------------------------
82        SampleGrabberCallback(){
83                InitializeCriticalSection(&critSection);
84                freezeCheck = 0;
85
86
87                bufferSetup             = false;
88                newFrame                        = false;
89                latestBufferLength      = 0;
90               
91                hEvent = CreateEvent(NULL, true, false, NULL);
92        }
93
94
95        //------------------------------------------------
96        ~SampleGrabberCallback(){
97                ptrBuffer = NULL;
98                DeleteCriticalSection(&critSection);
99                CloseHandle(hEvent);
100                if(bufferSetup){
101                        delete pixels;
102                }
103        }       
104       
105       
106        //------------------------------------------------
107        bool setupBuffer(int numBytesIn){
108                if(bufferSetup){
109                        return false;
110                }else{
111                        numBytes                        = numBytesIn;
112                        pixels                          = new unsigned char[numBytes];
113                        bufferSetup             = true;
114                        newFrame                        = false;
115                        latestBufferLength      = 0;
116                }
117                return true;
118        }
119
120
121        //------------------------------------------------
122    STDMETHODIMP_(ULONG) AddRef() { return 1; }
123    STDMETHODIMP_(ULONG) Release() { return 2; }
124
125
126        //------------------------------------------------
127    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject){
128        *ppvObject = static_cast<ISampleGrabberCB*>(this);
129        return S_OK;
130    }
131   
132   
133    //This method is meant to have less overhead
134        //------------------------------------------------
135    STDMETHODIMP SampleCB(double Time, IMediaSample *pSample){
136        if(WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0) return S_OK;
137 
138        HRESULT hr = pSample->GetPointer(&ptrBuffer); 
139                       
140        if(hr == S_OK){
141                latestBufferLength = pSample->GetActualDataLength();                   
142                if(latestBufferLength == numBytes){
143                                EnterCriticalSection(&critSection);
144                                memcpy(pixels, ptrBuffer, latestBufferLength); 
145                                        newFrame        = true;
146                                        freezeCheck = 1;
147                                LeaveCriticalSection(&critSection);
148                                SetEvent(hEvent);
149                        }else{
150                                printf("ERROR: SampleCB() - buffer sizes do not match\n");
151                        }
152                }
153                                               
154                return S_OK;
155    }
156   
157   
158    //This method is meant to have more overhead
159    STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen){
160        return E_NOTIMPL;
161    }
162
163        int freezeCheck;
164
165        int latestBufferLength;
166        int numBytes;
167        bool newFrame;
168        bool bufferSetup;
169        unsigned char * pixels;
170        unsigned char * ptrBuffer;
171        CRITICAL_SECTION critSection;
172        HANDLE hEvent; 
173};
174
175
176//////////////////////////////  VIDEO DEVICE  ////////////////////////////////
177
178// ----------------------------------------------------------------------
179//      Should this class also be the callback?                                                         
180//                                                                 
181// ----------------------------------------------------------------------
182
183videoDevice::videoDevice(){
184               
185                 pCaptureGraph      = NULL;     // Capture graph builder object
186                 pGraph             = NULL;     // Graph builder object
187             pControl           = NULL; // Media control object
188                 pVideoInputFilter  = NULL; // Video Capture filter
189                 pGrabber           = NULL; // Grabs frame
190                 pDestFilter            = NULL; // Null Renderer Filter
191                 pGrabberF                      = NULL; // Grabber Filter
192                 pMediaEvent            = NULL; 
193                 streamConf                     = NULL;
194                 pAmMediaType           = NULL;
195                 
196                 //This is our callback class that processes the frame.
197                 sgCallback                     = new SampleGrabberCallback();
198                 sgCallback->newFrame = false;
199
200                 //Default values for capture type
201                 videoType                      = MEDIASUBTYPE_RGB24;
202             connection         = PhysConn_Video_Composite;
203                 storeConn                      = 0;
204                 
205                 videoSize                      = 0;
206             width                      = 0;
207             height                     = 0;
208             tryWidth                   = 0;
209             tryHeight                  = 0;
210                 nFramesForReconnect= 10000;
211                 nFramesRunning     = 0;
212             myID                               = -1;
213             
214             tryDiffSize        = false;
215             useCrossbar        = false;
216                 readyToCapture         = false;
217                 sizeSet                        = false;
218                 setupStarted           = false;
219                 specificFormat         = false;
220                 autoReconnect          = false;
221                 requestedFrameTime = -1;
222                 
223                 memset(wDeviceName, 0, sizeof(WCHAR) * 255);
224                 memset(nDeviceName, 0, sizeof(char) * 255);
225             
226}
227
228
229// ----------------------------------------------------------------------
230//      The only place we are doing new                                                 
231//                                                                     
232// ----------------------------------------------------------------------
233
234void videoDevice::setSize(int w, int h){
235        if(sizeSet){
236                if(verbose)printf("SETUP: Error device size should not be set more than once \n");
237        }
238        else
239        {
240                width                           = w;
241                height                          = h;
242                videoSize                       = w*h*3;
243                sizeSet                         = true;
244                pixels                          = new unsigned char[videoSize];
245                pBuffer                         = new char[videoSize];
246
247                memset(pixels, 0 , videoSize);
248                sgCallback->setupBuffer(videoSize);
249               
250        }
251}
252
253
254// ----------------------------------------------------------------------
255//      Borrowed from the SDK, use it to take apart the graph from                                                     
256//  the capture device downstream to the null renderer                                                                   
257// ----------------------------------------------------------------------
258
259void videoDevice::NukeDownstream(IBaseFilter *pBF){
260        IPin *pP, *pTo;
261        ULONG u;
262        IEnumPins *pins = NULL;
263        PIN_INFO pininfo;
264        HRESULT hr = pBF->EnumPins(&pins);
265        pins->Reset();
266        while (hr == NOERROR)
267        {
268                hr = pins->Next(1, &pP, &u);
269                if (hr == S_OK && pP)
270                {
271                        pP->ConnectedTo(&pTo);
272                        if (pTo)
273                        {
274                                hr = pTo->QueryPinInfo(&pininfo);
275                                if (hr == NOERROR)
276                                {
277                                        if (pininfo.dir == PINDIR_INPUT)
278                                        {
279                                                NukeDownstream(pininfo.pFilter);
280                                                pGraph->Disconnect(pTo);
281                                                pGraph->Disconnect(pP);
282                                                pGraph->RemoveFilter(pininfo.pFilter);
283                                        }
284                                        pininfo.pFilter->Release();
285                                                                                pininfo.pFilter = NULL;
286                                }
287                                pTo->Release();
288                        }
289                        pP->Release();
290                }
291        }
292        if (pins) pins->Release();
293} 
294
295
296// ----------------------------------------------------------------------
297//      Also from SDK                                                   
298// ----------------------------------------------------------------------
299
300void videoDevice::destroyGraph(){
301        HRESULT hr = NULL;
302        int FuncRetval=0;
303        int NumFilters=0;
304
305        int i = 0;
306        while (hr == NOERROR)   
307        {
308                IEnumFilters * pEnum = 0;
309                ULONG cFetched;
310
311                // We must get the enumerator again every time because removing a filter from the graph
312                // invalidates the enumerator. We always get only the first filter from each enumerator.
313                hr = pGraph->EnumFilters(&pEnum);
314                if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->EnumFilters() failed. \n"); return; }
315
316                IBaseFilter * pFilter = NULL;
317                if (pEnum->Next(1, &pFilter, &cFetched) == S_OK)
318                {
319                        FILTER_INFO FilterInfo={0};
320                        hr = pFilter->QueryFilterInfo(&FilterInfo);
321                        FilterInfo.pGraph->Release();
322
323                        int count = 0;
324                        WCHAR buffer[255];
325                        memset(buffer, 0, 255 * sizeof(WCHAR));
326                                               
327                        while( count< 255 && FilterInfo.achName[count] != 0x00 ) 
328                        {
329                                buffer[count] = FilterInfo.achName[count];
330                                count++;
331                        }
332                       
333                        if (verbose) printf("SETUP: removing filter %ls...\n", buffer);
334                        hr = pGraph->RemoveFilter(pFilter);
335                        if (FAILED(hr)) { if(verbose)printf("SETUP: pGraph->RemoveFilter() failed. \n"); return; }
336                        if (verbose) printf("SETUP: filter removed %ls\n",buffer);
337                       
338                        pFilter->Release();
339                        pFilter = NULL;
340                }
341                else break;
342                pEnum->Release();
343                pEnum = NULL;
344                i++;
345        }
346
347 return;
348}
349
350
351// ----------------------------------------------------------------------
352// Our deconstructor, attempts to tear down graph and release filters etc
353// Does checking to make sure it only is freeing if it needs to
354// Probably could be a lot cleaner! :)                                                               
355// ----------------------------------------------------------------------
356
357videoDevice::~videoDevice(){
358
359        if(setupStarted){ if(verbose)printf("\nSETUP: Disconnecting device %i\n", myID); }
360        else{
361                if(sgCallback){
362                        sgCallback->Release();
363                        delete sgCallback;
364                }
365                return;
366        }
367               
368        HRESULT HR = NULL;
369       
370        //Stop the callback and free it
371    if( (sgCallback) && (pGrabber) )
372    {
373        pGrabber->SetCallback(NULL, 1);
374        if(verbose)printf("SETUP: freeing Grabber Callback\n");
375        sgCallback->Release(); 
376       
377                //delete our pixels
378                if(sizeSet){
379                         delete[] pixels;
380                         delete[] pBuffer;
381                }
382               
383                delete sgCallback;
384        }
385       
386        //Check to see if the graph is running, if so stop it.
387        if( (pControl) )
388        {
389                HR = pControl->Pause();
390                if (FAILED(HR)) if(verbose)printf("ERROR - Could not pause pControl\n");
391               
392                HR = pControl->Stop();
393                if (FAILED(HR)) if(verbose)printf("ERROR - Could not stop pControl\n");
394    }
395               
396    //Disconnect filters from capture device
397    if( (pVideoInputFilter) )NukeDownstream(pVideoInputFilter);
398
399        //Release and zero pointers to our filters etc
400        if( (pDestFilter) ){            if(verbose)printf("SETUP: freeing Renderer \n");
401                                                                (pDestFilter)->Release();
402                                                                (pDestFilter) = 0;
403        }       
404        if( (pVideoInputFilter) ){      if(verbose)printf("SETUP: freeing Capture Source \n");
405                                                                (pVideoInputFilter)->Release();         
406                                                                (pVideoInputFilter) = 0;
407        }
408        if( (pGrabberF) ){                      if(verbose)printf("SETUP: freeing Grabber Filter  \n");
409                                                                (pGrabberF)->Release();
410                                                                (pGrabberF) = 0;                       
411        }
412        if( (pGrabber) ){                       if(verbose)printf("SETUP: freeing Grabber  \n"); 
413                                                                (pGrabber)->Release();
414                                                                (pGrabber) = 0;                         
415        }
416        if( (pControl) ){                       if(verbose)printf("SETUP: freeing Control   \n");
417                                                                (pControl)->Release();
418                                                                (pControl) = 0;                         
419        }               
420        if( (pMediaEvent) ){            if(verbose)printf("SETUP: freeing Media Event  \n");
421                                                                (pMediaEvent)->Release();                               
422                                                                (pMediaEvent) = 0;             
423        }
424        if( (streamConf) ){             if(verbose)printf("SETUP: freeing Stream  \n");
425                                                                (streamConf)->Release();                                       
426                                                                (streamConf) = 0;                       
427        }
428
429        if( (pAmMediaType) ){           if(verbose)printf("SETUP: freeing Media Type  \n");
430                                                                MyDeleteMediaType(pAmMediaType);                       
431        }
432
433        if((pMediaEvent)){
434                        if(verbose)printf("SETUP: freeing Media Event  \n");
435                        (pMediaEvent)->Release();                                       
436                        (pMediaEvent) = 0; 
437        }
438
439        //Destroy the graph
440        if( (pGraph) )destroyGraph();
441
442        //Release and zero our capture graph and our main graph
443        if( (pCaptureGraph) ){          if(verbose)printf("SETUP: freeing Capture Graph \n");
444                                                                (pCaptureGraph)->Release();
445                                                                (pCaptureGraph) = 0;           
446        }
447        if( (pGraph) ){                         if(verbose)printf("SETUP: freeing Main Graph \n");
448                                                                (pGraph)->Release();                                   
449                                                                (pGraph) = 0;                           
450        }               
451
452        //delete our pointers
453        delete pDestFilter;
454        delete pVideoInputFilter;
455        delete pGrabberF;
456        delete pGrabber;
457        delete pControl;
458        delete streamConf;
459        delete pMediaEvent;
460        delete pCaptureGraph;
461        delete pGraph;
462
463        if(verbose)printf("SETUP: Device %i disconnected and freed\n\n",myID);
464}
465
466
467//////////////////////////////  VIDEO INPUT  ////////////////////////////////
468////////////////////////////  PUBLIC METHODS  ///////////////////////////////
469
470
471// ----------------------------------------------------------------------
472// Constructor - creates instances of videoDevice and adds the various
473// media subtypes to check.                                               
474// ----------------------------------------------------------------------
475
476videoInput::videoInput(){   
477        //start com
478        comInit();
479
480        devicesFound            = 0;
481        callbackSetCount        = 0;
482        bCallback                       = true;
483       
484    //setup a max no of device objects
485    for(int i=0; i<VI_MAX_CAMERAS; i++)  VDList[i] = new videoDevice();
486     
487    if(verbose)printf("\n***** VIDEOINPUT LIBRARY - %2.04f - TFW07 *****\n\n",VI_VERSION);
488
489        //added for the pixelink firewire camera
490        MEDIASUBTYPE_Y800 = (GUID)FOURCCMap(FCC('Y800'));
491        MEDIASUBTYPE_Y8   = (GUID)FOURCCMap(FCC('Y8'));
492        MEDIASUBTYPE_GREY = (GUID)FOURCCMap(FCC('GREY'));
493
494        //The video types we support
495        //in order of preference
496       
497        mediaSubtypes[0]        = MEDIASUBTYPE_RGB24;
498        mediaSubtypes[1]        = MEDIASUBTYPE_RGB32;
499        mediaSubtypes[2]        = MEDIASUBTYPE_RGB555;
500        mediaSubtypes[3]        = MEDIASUBTYPE_RGB565;
501        mediaSubtypes[4]        = MEDIASUBTYPE_YUY2;
502        mediaSubtypes[5]        = MEDIASUBTYPE_YVYU;
503        mediaSubtypes[6]        = MEDIASUBTYPE_YUYV;
504        mediaSubtypes[7]        = MEDIASUBTYPE_IYUV;
505        mediaSubtypes[8]        = MEDIASUBTYPE_UYVY;
506        mediaSubtypes[9]        = MEDIASUBTYPE_YV12;
507        mediaSubtypes[10]       = MEDIASUBTYPE_YVU9;
508        mediaSubtypes[11]       = MEDIASUBTYPE_Y411;
509        mediaSubtypes[12]       = MEDIASUBTYPE_Y41P;
510        mediaSubtypes[13]       = MEDIASUBTYPE_Y211;
511        mediaSubtypes[14]       = MEDIASUBTYPE_AYUV;
512
513        //non standard
514        mediaSubtypes[15]       = MEDIASUBTYPE_Y800;
515    mediaSubtypes[16]   = MEDIASUBTYPE_Y8;
516        mediaSubtypes[17]       = MEDIASUBTYPE_GREY;   
517       
518        //The video formats we support
519        formatTypes[VI_NTSC_M]          = AnalogVideo_NTSC_M;
520        formatTypes[VI_NTSC_M_J]        = AnalogVideo_NTSC_M_J;
521        formatTypes[VI_NTSC_433]        = AnalogVideo_NTSC_433;
522               
523        formatTypes[VI_PAL_B]           = AnalogVideo_PAL_B;
524        formatTypes[VI_PAL_D]           = AnalogVideo_PAL_D;
525        formatTypes[VI_PAL_G]           = AnalogVideo_PAL_G;
526        formatTypes[VI_PAL_H]           = AnalogVideo_PAL_H;
527        formatTypes[VI_PAL_I]           = AnalogVideo_PAL_I;
528        formatTypes[VI_PAL_M]           = AnalogVideo_PAL_M;
529        formatTypes[VI_PAL_N]           = AnalogVideo_PAL_N;
530        formatTypes[VI_PAL_NC]          = AnalogVideo_PAL_N_COMBO;
531       
532        formatTypes[VI_SECAM_B]         = AnalogVideo_SECAM_B;
533        formatTypes[VI_SECAM_D]         = AnalogVideo_SECAM_D;
534        formatTypes[VI_SECAM_G]         = AnalogVideo_SECAM_G;
535        formatTypes[VI_SECAM_H]         = AnalogVideo_SECAM_H;
536        formatTypes[VI_SECAM_K]         = AnalogVideo_SECAM_K;
537        formatTypes[VI_SECAM_K1]        = AnalogVideo_SECAM_K1;
538        formatTypes[VI_SECAM_L]         = AnalogVideo_SECAM_L;
539       
540       
541        propBrightness                          = VideoProcAmp_Brightness;
542        propContrast                            = VideoProcAmp_Contrast;
543        propHue                                         = VideoProcAmp_Hue;
544        propSaturation                          = VideoProcAmp_Saturation;
545        propSharpness                           = VideoProcAmp_Sharpness;
546        propGamma                                       = VideoProcAmp_Gamma;
547        propColorEnable                         = VideoProcAmp_ColorEnable;
548        propWhiteBalance                        = VideoProcAmp_WhiteBalance;
549        propBacklightCompensation       = VideoProcAmp_BacklightCompensation;
550        propGain                                        = VideoProcAmp_Gain;
551
552        propPan                                         = CameraControl_Pan;
553        propTilt                                        = CameraControl_Tilt;
554        propRoll                                        = CameraControl_Roll;
555        propZoom                                        = CameraControl_Zoom;
556        propExposure                            = CameraControl_Exposure;
557        propIris                                        = CameraControl_Iris;
558        propFocus                                       = CameraControl_Focus;
559                                               
560}
561
562
563// ----------------------------------------------------------------------
564// static - set whether messages get printed to console or not
565//                                           
566// ----------------------------------------------------------------------
567
568void videoInput::setVerbose(bool _verbose){
569        verbose = _verbose;
570}
571
572// ----------------------------------------------------------------------
573// change to use callback or regular capture
574// callback tells you when a new frame has arrived
575// but non-callback won't - but is single threaded
576// ----------------------------------------------------------------------
577void videoInput::setUseCallback(bool useCallback){
578        if(callbackSetCount == 0){
579                bCallback = useCallback;
580                callbackSetCount = 1;
581        }else{
582                printf("ERROR: setUseCallback can only be called before setup\n");
583        }
584}
585
586// ----------------------------------------------------------------------
587// Set the requested framerate - no guarantee you will get this
588//                                           
589// ----------------------------------------------------------------------
590
591void videoInput::setIdealFramerate(int deviceNumber, int idealFramerate){
592        if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return;
593       
594        if( idealFramerate > 0 ){
595                VDList[deviceNumber]->requestedFrameTime = (unsigned long)(10000000 / idealFramerate);
596        }
597}
598
599
600// ----------------------------------------------------------------------
601// Set the requested framerate - no guarantee you will get this
602//                                           
603// ----------------------------------------------------------------------
604
605void videoInput::setAutoReconnectOnFreeze(int deviceNumber, bool doReconnect, int numMissedFramesBeforeReconnect){
606        if(deviceNumber >= VI_MAX_CAMERAS) return;
607
608        VDList[deviceNumber]->autoReconnect                     = doReconnect;
609        VDList[deviceNumber]->nFramesForReconnect       = numMissedFramesBeforeReconnect;       
610
611}
612
613
614// ----------------------------------------------------------------------
615// Setup a device with the default settings
616//                                           
617// ----------------------------------------------------------------------
618
619bool videoInput::setupDevice(int deviceNumber){
620        if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
621
622        if(setup(deviceNumber))return true;
623        return false;
624}
625
626
627// ----------------------------------------------------------------------
628// Setup a device with the default size but specify input type
629//                                           
630// ----------------------------------------------------------------------
631
632bool videoInput::setupDevice(int deviceNumber, int connection){
633        if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
634
635        setPhyCon(deviceNumber, connection);
636        if(setup(deviceNumber))return true;
637        return false;
638}
639
640
641// ----------------------------------------------------------------------
642// Setup a device with the default connection but specify size
643//                                           
644// ----------------------------------------------------------------------
645
646bool videoInput::setupDevice(int deviceNumber, int w, int h){
647        if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
648
649        setAttemptCaptureSize(deviceNumber,w,h);
650        if(setup(deviceNumber))return true;
651        return false;
652}
653
654
655// ----------------------------------------------------------------------
656// Setup a device with specific size and connection
657//                                           
658// ----------------------------------------------------------------------
659
660bool videoInput::setupDevice(int deviceNumber, int w, int h, int connection){
661        if(deviceNumber >= VI_MAX_CAMERAS || VDList[deviceNumber]->readyToCapture) return false;
662
663        setAttemptCaptureSize(deviceNumber,w,h);
664        setPhyCon(deviceNumber, connection);
665        if(setup(deviceNumber))return true;
666        return false;
667}
668
669
670// ----------------------------------------------------------------------
671// Setup the default video format of the device
672// Must be called after setup!
673// See #define formats in header file (eg VI_NTSC_M )
674//                                           
675// ----------------------------------------------------------------------
676
677bool videoInput::setFormat(int deviceNumber, int format){
678        if(deviceNumber >= VI_MAX_CAMERAS || !VDList[deviceNumber]->readyToCapture) return false;
679       
680        bool returnVal = false;
681       
682        if(format >= 0 && format < VI_NUM_FORMATS){
683                VDList[deviceNumber]->formatType = formatTypes[format]; 
684                VDList[deviceNumber]->specificFormat = true;
685               
686                if(VDList[deviceNumber]->specificFormat){
687               
688                        HRESULT hr = getDevice(&VDList[deviceNumber]->pVideoInputFilter, deviceNumber, VDList[deviceNumber]->wDeviceName, VDList[deviceNumber]->nDeviceName);
689                        if(hr != S_OK){
690                                return false;
691                        }
692
693                        IAMAnalogVideoDecoder *pVideoDec = NULL;       
694                        hr = VDList[deviceNumber]->pCaptureGraph->FindInterface(NULL, &MEDIATYPE_Video, VDList[deviceNumber]->pVideoInputFilter, IID_IAMAnalogVideoDecoder, (void **)&pVideoDec);
695                       
696                        //in case the settings window some how freed them first
697                        if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter->Release();                 
698                        if(VDList[deviceNumber]->pVideoInputFilter)VDList[deviceNumber]->pVideoInputFilter = NULL; 
699
700                        if(FAILED(hr)){
701                                printf("SETUP: couldn't set requested format\n");
702                        }else{
703                                long lValue = 0;
704                                hr = pVideoDec->get_AvailableTVFormats(&lValue);
705                        if( SUCCEEDED(hr) && (lValue & VDList[deviceNumber]->formatType) )
706                                {
707                                hr = pVideoDec->put_TVFormat(VDList[deviceNumber]->formatType);
708                                        if( FAILED(hr) ){
709                                                printf("SETUP: couldn't set requested format\n");
710                                        }else{
711                                                returnVal = true;       
712                                        }
713                                }
714                               
715                                pVideoDec->Release();
716                        pVideoDec = NULL;                               
717                        }                       
718                }               
719        }
720       
721        return returnVal;
722}
723
724// ----------------------------------------------------------------------
725// Our static function for returning device names - thanks Peter!
726// Must call listDevices first.
727//                                           
728// ----------------------------------------------------------------------
729char videoInput::deviceNames[VI_MAX_CAMERAS][255]={{0}};
730
731char * videoInput::getDeviceName(int deviceID){
732        if( deviceID >= VI_MAX_CAMERAS ){
733                return NULL;
734        }
735        return deviceNames[deviceID];
736}
737
738
739// ----------------------------------------------------------------------
740// Our static function for finding num devices available etc
741//                                           
742// ----------------------------------------------------------------------
743
744int videoInput::listDevices(bool silent){ 
745
746    //COM Library Intialization
747        comInit();
748       
749    if(!silent)printf("\nVIDEOINPUT SPY MODE!\n\n");   
750   
751       
752        ICreateDevEnum *pDevEnum = NULL;
753        IEnumMoniker *pEnum = NULL;     
754        int deviceCounter = 0;
755       
756        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
757            CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, 
758            reinterpret_cast<void**>(&pDevEnum));
759           
760           
761        if (SUCCEEDED(hr))
762        {
763            // Create an enumerator for the video capture category.
764            hr = pDevEnum->CreateClassEnumerator(
765                CLSID_VideoInputDeviceCategory,
766                &pEnum, 0);
767               
768           if(hr == S_OK){
769           
770                         if(!silent)printf("SETUP: Looking For Capture Devices\n");
771                        IMoniker *pMoniker = NULL;
772
773                        while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
774                           
775                            IPropertyBag *pPropBag;
776                            hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 
777                                (void**)(&pPropBag));
778                               
779                            if (FAILED(hr)){
780                                pMoniker->Release();
781                                continue;  // Skip this one, maybe the next one will work.
782                            } 
783                           
784                           
785                                // Find the description or friendly name.
786                            VARIANT varName;
787                            VariantInit(&varName);
788                            hr = pPropBag->Read(L"Description", &varName, 0);
789                                           
790                            if (FAILED(hr)) hr = pPropBag->Read(L"FriendlyName", &varName, 0);
791                         
792                            if (SUCCEEDED(hr)){
793                           
794                                hr = pPropBag->Read(L"FriendlyName", &varName, 0);
795                               
796                                        int count = 0;
797                                        int maxLen = sizeof(deviceNames[0])/sizeof(deviceNames[0][0]) - 2;
798                                        while( varName.bstrVal[count] != 0x00 && count < maxLen) {
799                                                deviceNames[deviceCounter][count] = static_cast<char>(varName.bstrVal[count]);
800                                                count++;
801                                        }
802                                        deviceNames[deviceCounter][count] = 0;
803                                                 
804                                if(!silent)printf("SETUP: %i) %s \n",deviceCounter, deviceNames[deviceCounter]);
805                            }
806                           
807                            pPropBag->Release();
808                            pPropBag = NULL;
809                           
810                            pMoniker->Release();
811                            pMoniker = NULL;
812                           
813                            deviceCounter++;
814                        }   
815                       
816                        pDevEnum->Release();
817                        pDevEnum = NULL;
818                       
819                        pEnum->Release();
820                        pEnum = NULL;
821                }
822       
823                 if(!silent)printf("SETUP: %i Device(s) found\n\n", deviceCounter);
824        }
825       
826        comUnInit();
827       
828        return deviceCounter;           
829}
830
831
832// ----------------------------------------------------------------------
833//
834//                                           
835// ----------------------------------------------------------------------
836
837int videoInput::getWidth(int id){
838       
839        if(isDeviceSetup(id))
840        {
841                return VDList[id] ->width;
842        }
843       
844        return 0;
845       
846}
847
848
849// ----------------------------------------------------------------------
850//
851//                                           
852// ----------------------------------------------------------------------
853
854int videoInput::getHeight(int id){
855       
856        if(isDeviceSetup(id))
857        {
858                return VDList[id] ->height;
859        }
860       
861        return 0;
862       
863}
864
865
866// ----------------------------------------------------------------------
867//
868//                                           
869// ----------------------------------------------------------------------
870
871int videoInput::getSize(int id){
872       
873        if(isDeviceSetup(id))
874        {
875                return VDList[id] ->videoSize;
876        }
877       
878        return 0;
879       
880}
881
882
883// ----------------------------------------------------------------------
884// Uses a supplied buffer
885// ----------------------------------------------------------------------
886
887bool videoInput::getPixels(int id, unsigned char * dstBuffer, bool flipRedAndBlue, bool flipImage){
888       
889        bool success = false;
890
891        if(isDeviceSetup(id)){         
892                if(bCallback){         
893                        //callback capture     
894               
895                        DWORD result = WaitForSingleObject(VDList[id]->sgCallback->hEvent, 1000);
896                        if( result != WAIT_OBJECT_0) return false;
897                                               
898                        //double paranoia - mutexing with both event and critical section
899                        EnterCriticalSection(&VDList[id]->sgCallback->critSection);
900                       
901                                unsigned char * src = VDList[id]->sgCallback->pixels;
902                                unsigned char * dst = dstBuffer;
903                                int height                      = VDList[id]->height;
904                                int width                       = VDList[id]->width; 
905                       
906                                processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
907                                VDList[id]->sgCallback->newFrame = false;
908                               
909                        LeaveCriticalSection(&VDList[id]->sgCallback->critSection);     
910
911                        ResetEvent(VDList[id]->sgCallback->hEvent);
912                       
913                        success = true;
914                       
915                }
916                else{   
917                        //regular capture method
918                        long bufferSize = VDList[id]->videoSize;
919                        HRESULT hr = VDList[id]->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VDList[id]->pBuffer);
920                        if(hr==S_OK){
921                                int numBytes = VDList[id]->videoSize;                                   
922                                if (numBytes == bufferSize){
923                                       
924                                        unsigned char * src = (unsigned char * )VDList[id]->pBuffer;
925                                        unsigned char * dst = dstBuffer;
926                                        int height                      = VDList[id]->height;
927                                        int width                       = VDList[id]->width; 
928                                                                               
929                                        processPixels(src, dst, width, height, flipRedAndBlue, flipImage);
930                                        success = true;
931                                }else{
932                                        if(verbose)printf("ERROR: GetPixels() - bufferSizes do not match!\n");
933                                }
934                        }else{
935                                if(verbose)printf("ERROR: GetPixels() - Unable to grab frame for device %i\n", id);
936                        }                               
937                }
938        }
939       
940        return success;
941}
942
943
944// ----------------------------------------------------------------------
945// Returns a buffer
946// ----------------------------------------------------------------------
947unsigned char * videoInput::getPixels(int id, bool flipRedAndBlue, bool flipImage){
948
949        if(isDeviceSetup(id)){
950                getPixels(id, VDList[id]->pixels, flipRedAndBlue, flipImage);
951        }
952       
953        return VDList[id]->pixels;
954}
955
956
957
958// ----------------------------------------------------------------------
959//
960//                                           
961// ----------------------------------------------------------------------
962bool videoInput::isFrameNew(int id){
963        if(!isDeviceSetup(id)) return false;
964        if(!bCallback)return true;
965       
966        bool result = false;
967        bool freeze = false;
968       
969        //again super paranoia!
970        EnterCriticalSection(&VDList[id]->sgCallback->critSection);
971                result = VDList[id]->sgCallback->newFrame;
972
973                //we need to give it some time at the begining to start up so lets check after 400 frames
974                if(VDList[id]->nFramesRunning > 400 && VDList[id]->sgCallback->freezeCheck > VDList[id]->nFramesForReconnect ){
975                        freeze = true;
976                }
977               
978                //we increment the freezeCheck var here - the callback resets it to 1
979                //so as long as the callback is running this var should never get too high.
980                //if the callback is not running then this number will get high and trigger the freeze action below
981                VDList[id]->sgCallback->freezeCheck++;
982        LeaveCriticalSection(&VDList[id]->sgCallback->critSection);     
983
984        VDList[id]->nFramesRunning++;
985
986        if(freeze && VDList[id]->autoReconnect){
987                if(verbose)printf("ERROR: Device seems frozen - attempting to reconnect\n"); 
988                if( !restartDevice(VDList[id]->myID) ){
989                        if(verbose)printf("ERROR: Unable to reconnect to device\n");
990                }else{
991                        if(verbose)printf("SUCCESS: Able to reconnect to device\n");
992                }
993        }
994               
995        return result; 
996}
997
998
999// ----------------------------------------------------------------------
1000//
1001//                                           
1002// ----------------------------------------------------------------------
1003
1004bool videoInput::isDeviceSetup(int id){
1005       
1006        if(id<devicesFound && VDList[id]->readyToCapture)return true;
1007        else return false;
1008
1009}
1010
1011
1012// ----------------------------------------------------------------------
1013// Gives us a little pop up window to adjust settings           
1014// We do this in a seperate thread now!
1015// ----------------------------------------------------------------------
1016
1017
1018void __cdecl videoInput::basicThread(void * objPtr){
1019
1020        //get a reference to the video device
1021        //not a copy as we need to free the filter
1022        videoDevice * vd = *( (videoDevice **)(objPtr) );
1023        ShowFilterPropertyPages(vd->pVideoInputFilter); 
1024
1025        //now we free the filter and make sure it set to NULL
1026        if(vd->pVideoInputFilter)vd->pVideoInputFilter->Release();
1027        if(vd->pVideoInputFilter)vd->pVideoInputFilter = NULL;
1028
1029        return;
1030}
1031
1032void videoInput::showSettingsWindow(int id){ 
1033
1034        if(isDeviceSetup(id)){
1035
1036//              HANDLE myTempThread;
1037
1038                //we reconnect to the device as we have freed our reference to it
1039                //why have we freed our reference? because there seemed to be an issue
1040                //with some mpeg devices if we didn't
1041                HRESULT hr = getDevice(&VDList[id]->pVideoInputFilter, id, VDList[id]->wDeviceName, VDList[id]->nDeviceName);
1042                if(hr == S_OK){
1043                        // Modified by cmauri. Don't start a new thread
1044                        //myTempThread = (HANDLE)_beginthread(basicThread, 0, (void *)&VDList[id]); 
1045                        videoInput::basicThread ((void *)&VDList[id]);                 
1046                }
1047        }
1048}
1049
1050
1051// Set a video signal setting using IAMVideoProcAmp
1052bool videoInput::getVideoSettingFilter(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue){
1053        if( !isDeviceSetup(deviceID) )return false;
1054
1055        HRESULT hr;     
1056        bool isSuccessful = false;
1057       
1058        videoDevice * VD = VDList[deviceID];
1059       
1060        hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);     
1061        if (FAILED(hr)){
1062                printf("setVideoSetting - getDevice Error\n");
1063                return false;
1064        }
1065
1066        IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1067       
1068        hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1069        if(FAILED(hr)){
1070                printf("setVideoSetting - QueryInterface Error\n");
1071                if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1072                if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;         
1073                return false;                   
1074        }
1075       
1076        if (verbose) printf("Setting video setting %ld.\n", Property);
1077       
1078        pAMVideoProcAmp->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1079        if (verbose) printf("Range for video setting %ld: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", Property, min, max, SteppingDelta, defaultValue, flags);
1080        pAMVideoProcAmp->Get(Property, &currentValue, &flags);
1081       
1082        if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1083        if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1084        if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; 
1085                       
1086        return true;
1087       
1088}
1089
1090
1091// Set a video signal setting using IAMVideoProcAmp
1092bool videoInput::setVideoSettingFilterPct(int deviceID, long Property, float pctValue, long Flags){
1093        if( !isDeviceSetup(deviceID) )return false;
1094       
1095        long min, max, currentValue, flags, defaultValue, stepAmnt;
1096       
1097        if( !getVideoSettingFilter(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1098
1099        if(pctValue > 1.0)pctValue = 1.0;
1100        else if(pctValue < 0)pctValue = 0.0;
1101       
1102        float range = (float)max - (float)min;
1103        if(range <= 0)return false;     
1104        if(stepAmnt == 0) return false;
1105
1106        long value      = (long)( (float)min + range * pctValue ); 
1107        long rasterValue = value;
1108
1109        //if the range is the stepAmnt then it is just a switch
1110        //so we either set the value to low or high
1111        if( range == stepAmnt ){
1112                if( pctValue < 0.5)rasterValue = min;
1113                else rasterValue = max; 
1114        }else{
1115                //we need to rasterize the value to the stepping amnt
1116                long mod                = value % stepAmnt;
1117                float halfStep  = (float)stepAmnt * 0.5f;
1118                if( mod < halfStep ) rasterValue -= mod;
1119                else rasterValue += stepAmnt - mod;     
1120                printf("RASTER - pctValue is %f - value is %i - step is %i - mod is %i - rasterValue is %i\n", pctValue, value, stepAmnt, mod, rasterValue); 
1121        }
1122               
1123        return setVideoSettingFilter(deviceID, Property, rasterValue, Flags, false);
1124}
1125
1126
1127// Set a video signal setting using IAMVideoProcAmp
1128bool videoInput::setVideoSettingFilter(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1129        if( !isDeviceSetup(deviceID) )return false;
1130
1131        HRESULT hr;     
1132        bool isSuccessful = false;
1133       
1134        videoDevice * VD = VDList[deviceID];
1135       
1136        hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);     
1137        if (FAILED(hr)){
1138                printf("setVideoSetting - getDevice Error\n");
1139                return false;
1140        }
1141
1142        IAMVideoProcAmp *pAMVideoProcAmp = NULL;
1143       
1144        hr = VD->pVideoInputFilter->QueryInterface(IID_IAMVideoProcAmp, (void**)&pAMVideoProcAmp);
1145        if(FAILED(hr)){
1146                printf("setVideoSetting - QueryInterface Error\n");
1147                if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1148                if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;         
1149                return false;                   
1150        }
1151       
1152        if (verbose) printf("Setting video setting %ld.\n", Property);
1153        long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags = 0;
1154       
1155       
1156        pAMVideoProcAmp->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1157        if (verbose) printf("Range for video setting %ld: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", Property, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1158        pAMVideoProcAmp->Get(Property, &CurrVal, &CapsFlags);
1159       
1160        if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1161       
1162        if (useDefaultValue) {
1163                pAMVideoProcAmp->Set(Property, Default, VideoProcAmp_Flags_Auto);
1164        }
1165        else{
1166                // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1167                pAMVideoProcAmp->Set(Property, lValue, Flags);
1168        }
1169       
1170        if(pAMVideoProcAmp)pAMVideoProcAmp->Release();
1171        if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1172        if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; 
1173                       
1174        return true;
1175       
1176}
1177
1178
1179bool videoInput::setVideoSettingCameraPct(int deviceID, long Property, float pctValue, long Flags){
1180        if( !isDeviceSetup(deviceID) )return false;
1181       
1182        long min, max, currentValue, flags, defaultValue, stepAmnt;
1183       
1184        if( !getVideoSettingCamera(deviceID, Property, min, max, stepAmnt, currentValue, flags, defaultValue) )return false;
1185
1186        if(pctValue > 1.0)pctValue = 1.0;
1187        else if(pctValue < 0)pctValue = 0.0;
1188       
1189        float range = (float)max - (float)min;
1190        if(range <= 0)return false;     
1191        if(stepAmnt == 0) return false;
1192
1193        long value      = (long)( (float)min + range * pctValue ); 
1194        long rasterValue = value;
1195
1196        //if the range is the stepAmnt then it is just a switch
1197        //so we either set the value to low or high
1198        if( range == stepAmnt ){
1199                if( pctValue < 0.5)rasterValue = min;
1200                else rasterValue = max; 
1201        }else{
1202                //we need to rasterize the value to the stepping amnt
1203                long mod                = value % stepAmnt;
1204                float halfStep  = (float)stepAmnt * 0.5f;
1205                if( mod < halfStep ) rasterValue -= mod;
1206                else rasterValue += stepAmnt - mod;     
1207                printf("RASTER - pctValue is %f - value is %i - step is %i - mod is %i - rasterValue is %i\n", pctValue, value, stepAmnt, mod, rasterValue); 
1208        }
1209       
1210        return setVideoSettingCamera(deviceID, Property, rasterValue, Flags, false);
1211}
1212
1213
1214bool videoInput::setVideoSettingCamera(int deviceID, long Property, long lValue, long Flags, bool useDefaultValue){
1215        IAMCameraControl *pIAMCameraControl;
1216        if(isDeviceSetup(deviceID))
1217        {
1218                HRESULT hr;
1219                hr = getDevice(&VDList[deviceID]->pVideoInputFilter, deviceID, VDList[deviceID]->wDeviceName, VDList[deviceID]->nDeviceName);   
1220       
1221                if (verbose) printf("Setting video setting %ld.\n", Property);
1222                hr = VDList[deviceID]->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1223                if (FAILED(hr)) {
1224                        printf("Error\n");
1225                        return false;
1226                }
1227                else
1228                {
1229                        long CurrVal, Min, Max, SteppingDelta, Default, CapsFlags, AvailableCapsFlags;
1230                        pIAMCameraControl->GetRange(Property, &Min, &Max, &SteppingDelta, &Default, &AvailableCapsFlags);
1231                        if (verbose) printf("Range for video setting %ld: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", Property, Min, Max, SteppingDelta, Default, AvailableCapsFlags);
1232                        pIAMCameraControl->Get(Property, &CurrVal, &CapsFlags);
1233                        if (verbose) printf("Current value: %ld Flags %ld (%s)\n", CurrVal, CapsFlags, (CapsFlags == 1 ? "Auto" : (CapsFlags == 2 ? "Manual" : "Unknown")));
1234                        if (useDefaultValue) {
1235                                pIAMCameraControl->Set(Property, Default, CameraControl_Flags_Auto);
1236                        }
1237                        else
1238                        {
1239                                // Perhaps add a check that lValue and Flags are within the range aquired from GetRange above
1240                                pIAMCameraControl->Set(Property, lValue, Flags);
1241                        }
1242                        pIAMCameraControl->Release();
1243                        return true;
1244                }
1245        }
1246        return false;
1247}
1248
1249
1250
1251bool videoInput::getVideoSettingCamera(int deviceID, long Property, long &min, long &max, long &SteppingDelta, long &currentValue, long &flags, long &defaultValue){
1252        if( !isDeviceSetup(deviceID) )return false;
1253
1254        HRESULT hr;     
1255        bool isSuccessful = false;
1256       
1257        videoDevice * VD = VDList[deviceID];
1258       
1259        hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);     
1260        if (FAILED(hr)){
1261                printf("setVideoSetting - getDevice Error\n");
1262                return false;
1263        }
1264
1265        IAMCameraControl *pIAMCameraControl = NULL;
1266       
1267        hr = VD->pVideoInputFilter->QueryInterface(IID_IAMCameraControl, (void**)&pIAMCameraControl);
1268        if(FAILED(hr)){
1269                printf("setVideoSetting - QueryInterface Error\n");
1270                if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1271                if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL;         
1272                return false;                   
1273        }
1274       
1275        if (verbose) printf("Setting video setting %ld.\n", Property);
1276       
1277        pIAMCameraControl->GetRange(Property, &min, &max, &SteppingDelta, &defaultValue, &flags);
1278        if (verbose) printf("Range for video setting %ld: Min:%ld Max:%ld SteppingDelta:%ld Default:%ld Flags:%ld\n", Property, min, max, SteppingDelta, defaultValue, flags);
1279        pIAMCameraControl->Get(Property, &currentValue, &flags);
1280       
1281        if(pIAMCameraControl)pIAMCameraControl->Release();
1282        if(VD->pVideoInputFilter)VD->pVideoInputFilter->Release();
1283        if(VD->pVideoInputFilter)VD->pVideoInputFilter = NULL; 
1284                       
1285        return true;
1286       
1287}
1288
1289
1290// ----------------------------------------------------------------------
1291// Shutsdown the device, deletes the object and creates a new object
1292// so it is ready to be setup again                                         
1293// ----------------------------------------------------------------------
1294
1295void videoInput::stopDevice(int id){
1296        if(id < VI_MAX_CAMERAS)
1297        {       
1298                delete VDList[id];
1299                VDList[id] = new videoDevice();
1300        }
1301
1302}
1303
1304// ----------------------------------------------------------------------
1305// Restarts the device with the same settings it was using
1306//                                           
1307// ----------------------------------------------------------------------
1308
1309bool videoInput::restartDevice(int id){
1310        if(isDeviceSetup(id))
1311        {
1312                int conn                = VDList[id]->storeConn;
1313                int tmpW                = VDList[id]->width;
1314                int tmpH                = VDList[id]->height;
1315
1316                bool bFormat    = VDList[id]->specificFormat;
1317                long format     = VDList[id]->formatType;
1318
1319                int nReconnect  = VDList[id]->nFramesForReconnect;
1320                bool bReconnect = VDList[id]->autoReconnect;
1321
1322                unsigned long avgFrameTime = VDList[id]->requestedFrameTime;
1323       
1324                stopDevice(id);
1325
1326                //set our fps if needed
1327                if( avgFrameTime != -1){
1328                        VDList[id]->requestedFrameTime = avgFrameTime;
1329                }
1330
1331                if( setupDevice(id, tmpW, tmpH, conn) ){
1332                        //reapply the format - ntsc / pal etc
1333                        if( bFormat ){
1334                                setFormat(id, format);
1335                        }
1336                        if( bReconnect ){
1337                                setAutoReconnectOnFreeze(id, true, nReconnect);
1338                        }
1339                        return true;
1340                }
1341        }
1342        return false;
1343}
1344
1345// ----------------------------------------------------------------------
1346// Shuts down all devices, deletes objects and unitializes com if needed
1347//                                           
1348// ----------------------------------------------------------------------
1349videoInput::~videoInput(){
1350       
1351        for(int i = 0; i < VI_MAX_CAMERAS; i++)
1352        {
1353                delete VDList[i];
1354        }
1355        //Unitialize com
1356        comUnInit();
1357}
1358
1359
1360//////////////////////////////  VIDEO INPUT  ////////////////////////////////
1361////////////////////////////  PRIVATE METHODS  //////////////////////////////
1362
1363// ----------------------------------------------------------------------
1364// We only should init com if it hasn't been done so by our apps thread
1365// Use a static counter to keep track of other times it has been inited
1366// (do we need to worry about multithreaded apps?)                                             
1367// ----------------------------------------------------------------------
1368
1369bool videoInput::comInit(){
1370        HRESULT hr = NULL;
1371
1372        //no need for us to start com more than once
1373        if(comInitCount == 0 ){
1374
1375            // Initialize the COM library.
1376        //CoInitializeEx so videoInput can run in another thread
1377        #ifdef VI_COM_MULTI_THREADED
1378                hr = CoInitializeEx(NULL,COINIT_MULTITHREADED);
1379        #else
1380                hr = CoInitialize(NULL);
1381        #endif
1382                //this is the only case where there might be a problem
1383                //if another library has started com as single threaded
1384                //and we need it multi-threaded - send warning but don't fail
1385                if( hr == RPC_E_CHANGED_MODE){
1386                         if(verbose)printf("SETUP - COM already setup - threaded VI might not be possible\n");
1387                }
1388        }
1389
1390        comInitCount++; 
1391        return true;
1392}
1393
1394
1395// ----------------------------------------------------------------------
1396// Same as above but to unitialize com, decreases counter and frees com
1397// if no one else is using it                                           
1398// ----------------------------------------------------------------------
1399
1400bool videoInput::comUnInit(){
1401        if(comInitCount > 0)comInitCount--;             //decrease the count of instances using com
1402
1403        if(comInitCount == 0){
1404                CoUninitialize();       //if there are no instances left - uninitialize com
1405                return true;   
1406        }
1407       
1408        return false;
1409}
1410
1411
1412// ----------------------------------------------------------------------
1413// This is the size we ask for - we might not get it though :)
1414//                                           
1415// ----------------------------------------------------------------------
1416
1417void videoInput::setAttemptCaptureSize(int id, int w, int h){
1418       
1419        VDList[id]->tryWidth    = w;
1420        VDList[id]->tryHeight   = h;
1421        VDList[id]->tryDiffSize = true; 
1422       
1423}
1424
1425
1426// ----------------------------------------------------------------------
1427// Set the connection type
1428// (maybe move to private?)                                           
1429// ----------------------------------------------------------------------
1430
1431void videoInput::setPhyCon(int id, int conn){
1432
1433                switch(conn){
1434               
1435                        case 0:
1436                                VDList[id]->connection = PhysConn_Video_Composite;
1437                                break;
1438                        case 1:         
1439                                VDList[id]->connection = PhysConn_Video_SVideo;
1440                                break;
1441                        case 2:
1442                                VDList[id]->connection = PhysConn_Video_Tuner;
1443                                break;
1444                        case 3:
1445                                VDList[id]->connection = PhysConn_Video_USB;
1446                                break; 
1447                        case 4:
1448                                VDList[id]->connection = PhysConn_Video_1394;
1449                                break; 
1450                        default:
1451                                return; //if it is not these types don't set crossbar
1452                        break;
1453                }
1454
1455                VDList[id]->storeConn   = conn;
1456                VDList[id]->useCrossbar = true;
1457}
1458
1459
1460// ----------------------------------------------------------------------
1461// Check that we are not trying to setup a non-existant device
1462// Then start the graph building!                                           
1463// ----------------------------------------------------------------------
1464
1465bool videoInput::setup(int deviceNumber){
1466    devicesFound = getDeviceCount();
1467   
1468        if(deviceNumber>devicesFound-1)
1469    {   
1470        if(verbose)printf("SETUP: device[%i] not found - you have %i devices available\n", deviceNumber, devicesFound);
1471        if(devicesFound>=0) if(verbose)printf("SETUP: this means that the last device you can use is device[%i] \n",  devicesFound-1);
1472        return false;
1473    }
1474   
1475    if(VDList[deviceNumber]->readyToCapture)
1476    {
1477        if(verbose)printf("SETUP: can't setup, device %i is currently being used\n",VDList[deviceNumber]->myID);
1478        return false;
1479    }
1480   
1481    HRESULT hr = start(deviceNumber, VDList[deviceNumber]);
1482    if(hr == S_OK)return true;
1483        else return false;
1484}
1485
1486
1487// ----------------------------------------------------------------------
1488// Does both vertical buffer flipping and bgr to rgb swapping
1489// You have any combination of those.
1490// ----------------------------------------------------------------------
1491
1492void videoInput::processPixels(unsigned char * src, unsigned char * dst, int width, int height, bool bRGB, bool bFlip){
1493       
1494        int widthInBytes = width * 3;
1495        int numBytes = widthInBytes * height;
1496       
1497        if(!bRGB){
1498               
1499                int x = 0;
1500                int y = 0;
1501       
1502                if(bFlip){
1503                        for(int y = 0; y < height; y++){
1504                                memcpy(dst + (y * widthInBytes), src + ( (height -y -1) * widthInBytes), widthInBytes); 
1505                        }
1506                                                                       
1507                }else{
1508                        memcpy(dst, src, numBytes);
1509                }
1510        }else{
1511                if(bFlip){
1512                       
1513                        int x = 0;
1514                        int y = (height - 1) * widthInBytes;
1515                        src += y;
1516                       
1517                        for(int i = 0; i < numBytes; i+=3){
1518                                if(x >= width){
1519                                        x = 0;
1520                                        src -= widthInBytes*2;
1521                                }
1522                               
1523                                *dst = *(src+2);
1524                                dst++;
1525                               
1526                                *dst = *(src+1);
1527                                dst++; 
1528                               
1529                                *dst = *src;
1530                                dst++; 
1531                               
1532                                src+=3; 
1533                                x++;           
1534                        }
1535                }
1536                else{                                           
1537                        for(int i = 0; i < numBytes; i+=3){
1538                                *dst = *(src+2);
1539                                dst++;
1540                               
1541                                *dst = *(src+1);
1542                                dst++; 
1543                               
1544                                *dst = *src;
1545                                dst++; 
1546                               
1547                                src+=3;                 
1548                        }
1549                }
1550        }
1551}
1552
1553
1554//------------------------------------------------------------------------------------------
1555void videoInput::getMediaSubtypeAsString(GUID type, char * typeAsString){
1556
1557        memset (typeAsString,0, 8);
1558        if( type == MEDIASUBTYPE_RGB24) strncpy(typeAsString, "RGB24", 8);
1559        else if(type == MEDIASUBTYPE_RGB32) strncpy(typeAsString, "RGB32", 8);
1560        else if(type == MEDIASUBTYPE_RGB555)strncpy(typeAsString, "RGB555", 8);
1561        else if(type == MEDIASUBTYPE_RGB565)strncpy(typeAsString, "RGB565", 8);                         
1562        else if(type == MEDIASUBTYPE_YUY2)      strncpy(typeAsString, "YUY2", 8);
1563        else if(type == MEDIASUBTYPE_YVYU)      strncpy(typeAsString, "YVYU", 8);
1564        else if(type == MEDIASUBTYPE_YUYV)      strncpy(typeAsString, "YUYV", 8);
1565        else if(type == MEDIASUBTYPE_IYUV)      strncpy(typeAsString, "IYUV", 8);
1566        else if(type == MEDIASUBTYPE_UYVY)  strncpy(typeAsString, "UYVY", 8);
1567        else if(type == MEDIASUBTYPE_YV12)  strncpy(typeAsString, "YV12", 8);
1568        else if(type == MEDIASUBTYPE_YVU9)  strncpy(typeAsString, "YVU9", 8);
1569        else if(type == MEDIASUBTYPE_Y411)      strncpy(typeAsString, "Y411", 8);
1570        else if(type == MEDIASUBTYPE_Y41P)      strncpy(typeAsString, "Y41P", 8);
1571        else if(type == MEDIASUBTYPE_Y211)  strncpy(typeAsString, "Y211", 8);
1572        else if(type == MEDIASUBTYPE_AYUV)      strncpy(typeAsString, "AYUV", 8);
1573        else if(type == MEDIASUBTYPE_Y800)      strncpy(typeAsString, "Y800", 8);
1574        else if(type == MEDIASUBTYPE_Y8)        strncpy(typeAsString, "Y8", 8);
1575        else if(type == MEDIASUBTYPE_GREY)      strncpy(typeAsString, "GREY", 8);
1576        else strncpy(typeAsString, "OTHER", 8);
1577
1578}
1579
1580//-------------------------------------------------------------------------------------------
1581static void findClosestSizeAndSubtype(videoDevice * VD, int widthIn, int heightIn, int &widthOut, int &heightOut, GUID & mediatypeOut){
1582        HRESULT hr;
1583       
1584        //find perfect match or closest size
1585        int nearW                               = 9999999;
1586        int nearH                               = 9999999;
1587        bool foundClosestMatch  = true;
1588
1589        int iCount = 0; 
1590        int iSize = 0;
1591        hr = VD->streamConf->GetNumberOfCapabilities(&iCount, &iSize);
1592
1593        if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
1594        {
1595                //For each format type RGB24 YUV2 etc
1596            for (int iFormat = 0; iFormat < iCount; iFormat++)
1597            {
1598                        VIDEO_STREAM_CONFIG_CAPS scc;
1599                        AM_MEDIA_TYPE *pmtConfig;
1600                        hr =  VD->streamConf->GetStreamCaps(iFormat, &pmtConfig, (BYTE*)&scc);
1601                       
1602                        if (SUCCEEDED(hr)){
1603
1604                                //his is how many diff sizes are available for the format
1605                    int stepX = scc.OutputGranularityX;
1606                    int stepY = scc.OutputGranularityY;
1607                       
1608                        int tempW = 999999;
1609                        int tempH = 999999;
1610                               
1611                        //Don't want to get stuck in a loop
1612                        if(stepX < 1 || stepY < 1) continue;
1613                       
1614                        //if(verbose)printf("min is %i %i max is %i %i - res is %i %i \n", scc.MinOutputSize.cx, scc.MinOutputSize.cy,  scc.MaxOutputSize.cx,  scc.MaxOutputSize.cy, stepX, stepY);
1615                        //if(verbose)printf("min frame duration is %i  max duration is %i\n", scc.MinFrameInterval, scc.MaxFrameInterval);
1616
1617                        bool exactMatch         = false;
1618                        bool exactMatchX        = false;
1619                                bool exactMatchY        = false;
1620               
1621                    for(int x = scc.MinOutputSize.cx; x <= scc.MaxOutputSize.cx; x+= stepX){           
1622                        //If we find an exact match
1623                        if( widthIn == x ){
1624                                                exactMatchX = true;
1625                                tempW = x;                                             
1626                        }
1627                        //Otherwise lets find the closest match based on width
1628                        else if( abs(widthIn-x) < abs(widthIn-tempW) ){
1629                                tempW = x;                                             
1630                        }
1631                    }   
1632                           
1633                    for(int y = scc.MinOutputSize.cy; y <= scc.MaxOutputSize.cy; y+= stepY){           
1634                        //If we find an exact match
1635                        if( heightIn == y){
1636                                                exactMatchY = true;
1637                                tempH = y;                                                             
1638                        }
1639                        //Otherwise lets find the closest match based on height
1640                        else if( abs(heightIn-y) < abs(heightIn-tempH) ){
1641                                tempH = y;                                                             
1642                        }
1643                    }                                                       
1644                                       
1645                        //see if we have an exact match!
1646                        if(exactMatchX && exactMatchY){
1647                                foundClosestMatch = false;
1648                                exactMatch = true;
1649
1650                                        widthOut                = widthIn;
1651                                        heightOut               = heightIn;
1652                                        mediatypeOut    = pmtConfig->subtype;   
1653                        }       
1654                               
1655                        //otherwise lets see if this filters closest size is the closest
1656                        //available. the closest size is determined by the sum difference
1657                        //of the widths and heights
1658                        else if( abs(widthIn - tempW) + abs(heightIn - tempH)  < abs(widthIn - nearW) + abs(heightIn - nearH) )
1659                        {
1660                                nearW = tempW;
1661                                nearH = tempH;
1662
1663                                        widthOut                = nearW;
1664                                        heightOut               = nearH;
1665                                        mediatypeOut    = pmtConfig->subtype;   
1666                        }
1667                                       
1668                        MyDeleteMediaType(pmtConfig);
1669                                                                           
1670                        //If we have found an exact match no need to search anymore
1671                        if(exactMatch)break;
1672                }
1673             }
1674        }       
1675
1676}
1677
1678
1679//---------------------------------------------------------------------------------------------------
1680static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHeight, GUID mediatype){
1681        VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
1682
1683        //store current size
1684        int tmpWidth  = HEADER(pVih)->biWidth;
1685        int tmpHeight = HEADER(pVih)->biHeight; 
1686        AM_MEDIA_TYPE * tmpType = NULL;
1687       
1688        HRESULT hr = VD->streamConf->GetFormat(&tmpType);
1689        if(hr != S_OK)return false;
1690
1691        //set new size:
1692        //width and height
1693        HEADER(pVih)->biWidth  = attemptWidth;
1694        HEADER(pVih)->biHeight = attemptHeight; 
1695
1696        VD->pAmMediaType->formattype = FORMAT_VideoInfo;
1697        VD->pAmMediaType->majortype  = MEDIATYPE_Video; 
1698        VD->pAmMediaType->subtype        = mediatype;
1699       
1700        //buffer size
1701        VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight*3;
1702       
1703        //set fps if requested
1704        if( VD->requestedFrameTime != -1){
1705                pVih->AvgTimePerFrame = VD->requestedFrameTime;
1706        }               
1707
1708        //okay lets try new size       
1709        hr = VD->streamConf->SetFormat(VD->pAmMediaType);                 
1710        if(hr == S_OK){
1711                if( tmpType != NULL )MyDeleteMediaType(tmpType);
1712                return true;
1713        }else{
1714                VD->streamConf->SetFormat(tmpType);             
1715                if( tmpType != NULL )MyDeleteMediaType(tmpType);
1716        }
1717
1718        return false;
1719}
1720
1721// ----------------------------------------------------------------------
1722// Where all the work happens!
1723// Attempts to build a graph for the specified device                                   
1724// ----------------------------------------------------------------------
1725
1726int videoInput::start(int deviceID, videoDevice *VD){
1727
1728        HRESULT hr                      = NULL;
1729        VD->myID                        = deviceID;
1730        VD->setupStarted        = true;
1731    CAPTURE_MODE                = PIN_CATEGORY_CAPTURE; //Don't worry - it ends up being preview (which is faster)
1732        callbackSetCount        = 1;  //make sure callback method is not changed after setup called
1733
1734    if(verbose)printf("SETUP: Setting up device %i\n",deviceID);
1735
1736        // CREATE THE GRAPH BUILDER //
1737    // Create the filter graph manager and query for interfaces.
1738    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void **)&VD->pCaptureGraph);
1739    if (FAILED(hr))     // FAILED is a macro that tests the return value
1740    {
1741        if(verbose)printf("ERROR - Could not create the Filter Graph Manager\n");
1742        return hr;
1743    }
1744   
1745        //FITLER GRAPH MANAGER//
1746    // Create the Filter Graph Manager.
1747    hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&VD->pGraph);
1748    if (FAILED(hr))
1749    {
1750                if(verbose)printf("ERROR - Could not add the graph builder!\n");
1751            stopDevice(deviceID);
1752        return hr;
1753        }
1754   
1755    //SET THE FILTERGRAPH//
1756    hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph);
1757        if (FAILED(hr))
1758    {
1759                if(verbose)printf("ERROR - Could not set filtergraph\n");
1760            stopDevice(deviceID);
1761        return hr;
1762        }
1763
1764        //MEDIA CONTROL (START/STOPS STREAM)//
1765        // Using QueryInterface on the graph builder,
1766    // Get the Media Control object.
1767    hr = VD->pGraph->QueryInterface(IID_IMediaControl, (void **)&VD->pControl);
1768    if (FAILED(hr))
1769    {
1770        if(verbose)printf("ERROR - Could not create the Media Control object\n");
1771        stopDevice(deviceID);
1772        return hr;
1773    }
1774       
1775   
1776        //FIND VIDEO DEVICE AND ADD TO GRAPH//
1777        //gets the device specified by the second argument. 
1778        hr = getDevice(&VD->pVideoInputFilter, deviceID, VD->wDeviceName, VD->nDeviceName);
1779
1780        if (SUCCEEDED(hr)){
1781                if(verbose)printf("SETUP: %s\n", VD->nDeviceName);
1782                hr = VD->pGraph->AddFilter(VD->pVideoInputFilter, VD->wDeviceName);
1783        }else{
1784        if(verbose)printf("ERROR - Could not find specified video device\n");
1785        stopDevice(deviceID);
1786        return hr;             
1787        }
1788
1789        //LOOK FOR PREVIEW PIN IF THERE IS NONE THEN WE USE CAPTURE PIN AND THEN SMART TEE TO PREVIEW
1790        IAMStreamConfig *streamConfTest = NULL;
1791    hr = VD->pCaptureGraph->FindInterface(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&streamConfTest);               
1792        if(FAILED(hr)){
1793                if(verbose)printf("SETUP: Couldn't find preview pin using SmartTee\n");
1794        }else{
1795                 CAPTURE_MODE = PIN_CATEGORY_PREVIEW;
1796                 streamConfTest->Release();
1797                 streamConfTest = NULL;
1798        }
1799
1800        //CROSSBAR (SELECT PHYSICAL INPUT TYPE)//
1801        //my own function that checks to see if the device can support a crossbar and if so it routes it. 
1802        //webcams tend not to have a crossbar so this function will also detect a webcams and not apply the crossbar
1803        if(VD->useCrossbar)
1804        {
1805                if(verbose)printf("SETUP: Checking crossbar\n");
1806                routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE);
1807        }
1808
1809
1810        //we do this because webcams don't have a preview mode
1811        hr = VD->pCaptureGraph->FindInterface(&CAPTURE_MODE, &MEDIATYPE_Video, VD->pVideoInputFilter, IID_IAMStreamConfig, (void **)&VD->streamConf);
1812        if(FAILED(hr)){
1813                if(verbose)printf("ERROR: Couldn't config the stream!\n");
1814                stopDevice(deviceID);
1815                return hr;
1816        }
1817       
1818        //NOW LETS DEAL WITH GETTING THE RIGHT SIZE
1819        hr = VD->streamConf->GetFormat(&VD->pAmMediaType);
1820        if(FAILED(hr)){
1821                if(verbose)printf("ERROR: Couldn't getFormat for pAmMediaType!\n");
1822                stopDevice(deviceID);
1823                return hr;
1824        }
1825
1826        VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat);
1827        int currentWidth        =  HEADER(pVih)->biWidth;
1828        int currentHeight       =  HEADER(pVih)->biHeight;
1829
1830        bool customSize = VD->tryDiffSize;
1831        bool foundSize  = false;
1832
1833        if(customSize){
1834                if(verbose)     printf("SETUP: Default Format is set to %i by %i \n", currentWidth, currentHeight);
1835               
1836                char guidStr[8];
1837                for(int i = 0; i < VI_NUM_TYPES; i++){
1838                       
1839                        getMediaSubtypeAsString(mediaSubtypes[i], guidStr);
1840
1841                        if(verbose)printf("SETUP: trying format %s @ %i by %i\n", guidStr, VD->tryWidth, VD->tryHeight);
1842                        if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){
1843                                VD->setSize(VD->tryWidth, VD->tryHeight);
1844                                foundSize = true;
1845                                break;
1846                        }
1847                }
1848               
1849                //if we didn't find the requested size - lets try and find the closest matching size
1850                if( foundSize == false ){
1851                        if( verbose )printf("SETUP: couldn't find requested size - searching for closest matching size\n");
1852
1853                        int closestWidth                = -1;
1854                        int closestHeight               = -1;
1855                        GUID newMediaSubtype;
1856
1857                        findClosestSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, closestWidth, closestHeight, newMediaSubtype);
1858                               
1859                        if( closestWidth != -1 && closestHeight != -1){
1860                                getMediaSubtypeAsString(newMediaSubtype, guidStr);
1861
1862                                if(verbose)printf("SETUP: closest supported size is %s @ %i %i\n", guidStr, closestWidth, closestHeight);
1863                                if( setSizeAndSubtype(VD, closestWidth, closestHeight, newMediaSubtype) ){
1864                                        VD->setSize(closestWidth, closestHeight);
1865                                        foundSize = true;
1866                                }
1867                        }
1868                }
1869        }
1870       
1871        //if we didn't specify a custom size or if we did but couldn't find it lets setup with the default settings
1872        if(customSize == false || foundSize == false){
1873                if( VD->requestedFrameTime != -1 ){
1874                        pVih->AvgTimePerFrame  = VD->requestedFrameTime;
1875                        hr = VD->streamConf->SetFormat(VD->pAmMediaType);               
1876                } 
1877                VD->setSize(currentWidth, currentHeight);
1878        }
1879
1880        //SAMPLE GRABBER (ALLOWS US TO GRAB THE BUFFER)//
1881        // Create the Sample Grabber.
1882        hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER,IID_IBaseFilter, (void**)&VD->pGrabberF);
1883        if (FAILED(hr)){
1884                if(verbose)printf("Could not Create Sample Grabber - CoCreateInstance()\n");
1885                stopDevice(deviceID);
1886                return hr;
1887        }
1888
1889        hr = VD->pGraph->AddFilter(VD->pGrabberF, L"Sample Grabber");
1890        if (FAILED(hr)){
1891                if(verbose)printf("Could not add Sample Grabber - AddFilter()\n");
1892                stopDevice(deviceID);
1893                return hr;
1894        }
1895       
1896        hr = VD->pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&VD->pGrabber);
1897        if (FAILED(hr)){
1898                if(verbose)printf("ERROR: Could not query SampleGrabber\n");
1899                stopDevice(deviceID);
1900                return hr;
1901        }
1902       
1903               
1904        //Set Params - One Shot should be false unless you want to capture just one buffer
1905        hr = VD->pGrabber->SetOneShot(FALSE);
1906        if(bCallback){ 
1907                hr = VD->pGrabber->SetBufferSamples(FALSE);     
1908        }else{
1909                hr = VD->pGrabber->SetBufferSamples(TRUE);     
1910        }
1911               
1912        if(bCallback){
1913                //Tell the grabber to use our callback function - 0 is for SampleCB and 1 for BufferCB
1914                //We use SampleCB
1915                hr = VD->pGrabber->SetCallback(VD->sgCallback, 0); 
1916                if (FAILED(hr)){
1917                        if(verbose)printf("ERROR: problem setting callback\n"); 
1918                        stopDevice(deviceID);
1919                        return hr;
1920                }else{
1921                        if(verbose)printf("SETUP: Capture callback set\n");
1922                }
1923        }
1924       
1925        //MEDIA CONVERSION
1926        //Get video properties from the stream's mediatype and apply to the grabber (otherwise we don't get an RGB image)       
1927        //zero the media type - lets try this :) - maybe this works?
1928        AM_MEDIA_TYPE mt;
1929        ZeroMemory(&mt,sizeof(AM_MEDIA_TYPE));
1930       
1931        mt.majortype    = MEDIATYPE_Video;
1932        mt.subtype              = MEDIASUBTYPE_RGB24;
1933        mt.formattype   = FORMAT_VideoInfo;
1934       
1935        //VD->pAmMediaType->subtype = VD->videoType;
1936        hr = VD->pGrabber->SetMediaType(&mt);
1937       
1938        //lets try freeing our stream conf here too
1939        //this will fail if the device is already running
1940        if(VD->streamConf){
1941                VD->streamConf->Release();
1942                VD->streamConf = NULL;
1943        }else{
1944                if(verbose)printf("ERROR: connecting device - prehaps it is already being used?\n");
1945                stopDevice(deviceID);
1946                return S_FALSE;
1947        }
1948
1949
1950        //NULL RENDERER//
1951        //used to give the video stream somewhere to go to. 
1952        hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)(&VD->pDestFilter));
1953        if (FAILED(hr)){
1954                if(verbose)printf("ERROR: Could not create filter - NullRenderer\n");
1955                stopDevice(deviceID);
1956                return hr;
1957        }
1958       
1959        hr = VD->pGraph->AddFilter(VD->pDestFilter, L"NullRenderer");   
1960        if (FAILED(hr)){
1961                if(verbose)printf("ERROR: Could not add filter - NullRenderer\n");
1962                stopDevice(deviceID);
1963                return hr;
1964        }
1965       
1966        //RENDER STREAM//
1967        //This is where the stream gets put together.
1968        hr = VD->pCaptureGraph->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, VD->pVideoInputFilter, VD->pGrabberF, VD->pDestFilter);   
1969
1970        if (FAILED(hr)){
1971                if(verbose)printf("ERROR: Could not connect pins - RenderStream()\n");
1972                stopDevice(deviceID);
1973                return hr;
1974        }
1975
1976
1977        //EXP - lets try setting the sync source to null - and make it run as fast as possible
1978        {
1979                IMediaFilter *pMediaFilter = 0;
1980                hr = VD->pGraph->QueryInterface(IID_IMediaFilter, (void**)&pMediaFilter);
1981                if (FAILED(hr)){
1982                        if(verbose)printf("ERROR: Could not get IID_IMediaFilter interface\n");
1983                }else{
1984                        pMediaFilter->SetSyncSource(NULL);
1985                        pMediaFilter->Release();
1986                }
1987        }
1988
1989
1990        //LETS RUN THE STREAM!
1991        hr = VD->pControl->Run();
1992
1993        if (FAILED(hr)){
1994                 if(verbose)printf("ERROR: Could not start graph\n");
1995                 stopDevice(deviceID);
1996                 return hr;
1997        }
1998       
1999       
2000        //MAKE SURE THE DEVICE IS SENDING VIDEO BEFORE WE FINISH
2001        if(!bCallback){
2002               
2003                long bufferSize = VD->videoSize;
2004               
2005                while( hr != S_OK){
2006                        hr = VD->pGrabber->GetCurrentBuffer(&bufferSize, (long *)VD->pBuffer);
2007                        Sleep(10);
2008                }
2009       
2010        }
2011               
2012        if(verbose)printf("SETUP: Device is setup and ready to capture.\n\n");
2013        VD->readyToCapture = true; 
2014               
2015        //Release filters - seen someone else do this
2016        //looks like it solved the freezes
2017       
2018        //if we release this then we don't have access to the settings
2019        //we release our video input filter but then reconnect with it
2020        //each time we need to use it
2021        VD->pVideoInputFilter->Release();               
2022        VD->pVideoInputFilter = NULL;           
2023       
2024        VD->pGrabberF->Release();
2025        VD->pGrabberF = NULL;
2026       
2027        VD->pDestFilter->Release();
2028        VD->pDestFilter = NULL;
2029       
2030        return S_OK;
2031} 
2032
2033
2034// ----------------------------------------------------------------------
2035// Returns number of good devices
2036//                                   
2037// ----------------------------------------------------------------------
2038
2039int videoInput::getDeviceCount(){ 
2040
2041       
2042        ICreateDevEnum *pDevEnum = NULL;
2043        IEnumMoniker *pEnum = NULL;     
2044        int deviceCounter = 0;
2045       
2046        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
2047            CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, 
2048            reinterpret_cast<void**>(&pDevEnum));
2049           
2050           
2051        if (SUCCEEDED(hr))
2052        {
2053            // Create an enumerator for the video capture category.
2054            hr = pDevEnum->CreateClassEnumerator(
2055                CLSID_VideoInputDeviceCategory,
2056                &pEnum, 0);
2057               
2058           if(hr == S_OK){
2059                        IMoniker *pMoniker = NULL;
2060                        while (pEnum->Next(1, &pMoniker, NULL) == S_OK){
2061                           
2062                            IPropertyBag *pPropBag;
2063                            hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, 
2064                                (void**)(&pPropBag));
2065                               
2066                            if (FAILED(hr)){
2067                                pMoniker->Release();
2068                                continue;  // Skip this one, maybe the next one will work.
2069                            } 
2070                         
2071                            pPropBag->Release();
2072                            pPropBag = NULL;
2073                           
2074                            pMoniker->Release();
2075                            pMoniker = NULL;
2076                           
2077                            deviceCounter++;
2078                        }   
2079
2080                        pEnum->Release();
2081                        pEnum = NULL;
2082                }
2083
2084                pDevEnum->Release();
2085                pDevEnum = NULL;
2086        }
2087        return deviceCounter;   
2088}
2089   
2090
2091// ----------------------------------------------------------------------
2092// Do we need this? 
2093//   
2094// Enumerate all of the video input devices
2095// Return the filter with a matching friendly name                               
2096// ----------------------------------------------------------------------   
2097
2098HRESULT videoInput::getDevice(IBaseFilter** gottaFilter, int deviceId, WCHAR * wDeviceName, char * nDeviceName){
2099        BOOL done = false;
2100        int deviceCounter = 0;
2101
2102        // Create the System Device Enumerator.
2103        ICreateDevEnum *pSysDevEnum = NULL;
2104        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum);
2105        if (FAILED(hr))
2106        {
2107                return hr;
2108        }
2109
2110        // Obtain a class enumerator for the video input category.
2111        IEnumMoniker *pEnumCat = NULL;
2112        hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0);
2113
2114        if (hr == S_OK) 
2115        {
2116                // Enumerate the monikers.
2117                IMoniker *pMoniker = NULL;
2118                ULONG cFetched;
2119                while ((pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) && (!done))
2120                {
2121                        if(deviceCounter == deviceId)
2122                        {
2123                                // Bind the first moniker to an object
2124                                IPropertyBag *pPropBag;
2125                                hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag);
2126                                if (SUCCEEDED(hr))
2127                                {
2128                                        // To retrieve the filter's friendly name, do the following:
2129                                        VARIANT varName;
2130                                        VariantInit(&varName);
2131                                        hr = pPropBag->Read(L"FriendlyName", &varName, 0);
2132                                        if (SUCCEEDED(hr))
2133                                        {               
2134                                               
2135                                                //copy the name to nDeviceName & wDeviceName
2136                                                int count = 0;
2137                                                while( varName.bstrVal[count] != 0x00 ) {
2138                                         wDeviceName[count] = varName.bstrVal[count];
2139                                         nDeviceName[count] = (char)varName.bstrVal[count];
2140                                         count++;
2141                                }
2142                               
2143                                                // We found it, so send it back to the caller
2144                                                hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)gottaFilter);
2145                                                done = true;
2146                                        }
2147                                        VariantClear(&varName); 
2148                                        pPropBag->Release();
2149                                        pPropBag = NULL;
2150                                        pMoniker->Release();
2151                                        pMoniker = NULL;
2152                                }
2153                        }
2154                        deviceCounter++;
2155                }
2156                pEnumCat->Release();
2157                pEnumCat = NULL;
2158        }
2159        pSysDevEnum->Release();
2160        pSysDevEnum = NULL;
2161       
2162        if (done) {
2163                return hr;      // found it, return native error
2164        } else {
2165                return VFW_E_NOT_FOUND; // didn't find it error
2166        }
2167}
2168 
2169 
2170// ----------------------------------------------------------------------
2171// Show the property pages for a filter
2172// This is stolen from the DX9 SDK
2173// ----------------------------------------------------------------------
2174
2175HRESULT videoInput::ShowFilterPropertyPages(IBaseFilter *pFilter){
2176
2177        ISpecifyPropertyPages *pProp;
2178        HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp);
2179        if (SUCCEEDED(hr)) 
2180        {
2181                // Get the filter's name and IUnknown pointer.
2182                FILTER_INFO FilterInfo;
2183                hr = pFilter->QueryFilterInfo(&FilterInfo); 
2184                IUnknown *pFilterUnk;
2185                pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk);
2186
2187                // Show the page.
2188                CAUUID caGUID;
2189                pProp->GetPages(&caGUID);
2190                pProp->Release();
2191                OleCreatePropertyFrame(
2192                        NULL,                   // Parent window
2193                        0, 0,                   // Reserved
2194                        FilterInfo.achName,     // Caption for the dialog box
2195                        1,                      // Number of objects (just the filter)
2196                        &pFilterUnk,            // Array of object pointers.
2197                        caGUID.cElems,          // Number of property pages
2198                        caGUID.pElems,          // Array of property page CLSIDs
2199                        0,                      // Locale identifier
2200                        0, NULL                 // Reserved
2201                );
2202
2203                // Clean up.
2204                if(pFilterUnk)pFilterUnk->Release();
2205                if(FilterInfo.pGraph)FilterInfo.pGraph->Release(); 
2206                CoTaskMemFree(caGUID.pElems);
2207        }
2208        return hr;
2209}
2210   
2211   
2212// ----------------------------------------------------------------------
2213// This code was also brazenly stolen from the DX9 SDK
2214// Pass it a file name in wszPath, and it will save the filter graph to that file.
2215// ----------------------------------------------------------------------
2216
2217HRESULT videoInput::SaveGraphFile(IGraphBuilder *pGraph, WCHAR *wszPath) {
2218    const WCHAR wszStreamName[] = L"ActiveMovieGraph"; 
2219    HRESULT hr;
2220    IStorage *pStorage = NULL;
2221
2222        // First, create a document file which will hold the GRF file
2223        hr = StgCreateDocfile(
2224        wszPath,
2225        STGM_CREATE | STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
2226        0, &pStorage);
2227    if(FAILED(hr)) 
2228    {
2229        return hr;
2230    }
2231
2232        // Next, create a stream to store.
2233    IStream *pStream;
2234    hr = pStorage->CreateStream(
2235                wszStreamName,
2236        STGM_WRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
2237        0, 0, &pStream);
2238    if (FAILED(hr)) 
2239    {
2240        pStorage->Release();   
2241        return hr;
2242    }
2243
2244        // The IPersistStream converts a stream into a persistent object.
2245    IPersistStream *pPersist = NULL;
2246    pGraph->QueryInterface(IID_IPersistStream, reinterpret_cast<void**>(&pPersist));
2247    hr = pPersist->Save(pStream, TRUE);
2248    pStream->Release();
2249    pPersist->Release();
2250    if (SUCCEEDED(hr)) 
2251    {
2252        hr = pStorage->Commit(STGC_DEFAULT);
2253    }
2254    pStorage->Release();
2255    return hr;
2256}
2257
2258
2259// ----------------------------------------------------------------------
2260// For changing the input types
2261//
2262// ---------------------------------------------------------------------- 
2263
2264HRESULT videoInput::routeCrossbar(ICaptureGraphBuilder2 **ppBuild, IBaseFilter **pVidInFilter, int conType, GUID captureMode){
2265   
2266    //create local ICaptureGraphBuilder2
2267        ICaptureGraphBuilder2 *pBuild = NULL;
2268        pBuild = *ppBuild;
2269       
2270        //create local IBaseFilter
2271        IBaseFilter *pVidFilter = NULL;
2272        pVidFilter = * pVidInFilter;
2273       
2274        // Search upstream for a crossbar.
2275        IAMCrossbar *pXBar1 = NULL;
2276        HRESULT hr = pBuild->FindInterface(&LOOK_UPSTREAM_ONLY, NULL, pVidFilter,
2277                IID_IAMCrossbar, (void**)&pXBar1);
2278        if (SUCCEEDED(hr)) 
2279        {
2280           
2281            bool foundDevice = false;
2282           
2283            if(verbose)printf("SETUP: You are not a webcam! Setting Crossbar\n");
2284            pXBar1->Release();
2285           
2286            IAMCrossbar *Crossbar;
2287            hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Interleaved, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
2288           
2289            if(hr != NOERROR){
2290                hr = pBuild->FindInterface(&captureMode, &MEDIATYPE_Video, pVidFilter, IID_IAMCrossbar, (void **)&Crossbar);
2291                }
2292
2293                LONG lInpin, lOutpin;
2294                hr = Crossbar->get_PinCounts(&lOutpin , &lInpin); 
2295                               
2296                BOOL IPin=TRUE; LONG pIndex=0 , pRIndex=0 , pType=0;
2297               
2298                while( pIndex < lInpin)
2299                {
2300                        hr = Crossbar->get_CrossbarPinInfo( IPin , pIndex , &pRIndex , &pType); 
2301               
2302                        if( pType == conType){
2303                                        if(verbose)printf("SETUP: Found Physical Interface");                           
2304                                       
2305                                        switch(conType){
2306
2307                                                case PhysConn_Video_Composite:
2308                                                        if(verbose)printf(" - Composite\n");
2309                                                        break;
2310                                                case PhysConn_Video_SVideo:     
2311                                                        if(verbose)printf(" - S-Video\n");     
2312                                                        break;
2313                                                case PhysConn_Video_Tuner:
2314                                                        if(verbose)printf(" - Tuner\n");
2315                                                        break;
2316                                                case PhysConn_Video_USB:
2317                                                         if(verbose)printf(" - USB\n");
2318                                                        break; 
2319                                                case PhysConn_Video_1394:
2320                                                        if(verbose)printf(" - Firewire\n");
2321                                                        break;
2322                                        }                               
2323                                                       
2324                                foundDevice = true;
2325                                break;
2326                        }
2327                        pIndex++;
2328               
2329                }
2330               
2331                if(foundDevice){
2332                        BOOL OPin=FALSE; LONG pOIndex=0 , pORIndex=0 , pOType=0;
2333                        while( pOIndex < lOutpin)
2334                        {
2335                                hr = Crossbar->get_CrossbarPinInfo( OPin , pOIndex , &pORIndex , &pOType); 
2336                                if( pOType == PhysConn_Video_VideoDecoder)
2337                                        break;
2338                        }
2339                        Crossbar->Route(pOIndex,pIndex); 
2340                }else{
2341                        if(verbose)printf("SETUP: Didn't find specified Physical Connection type. Using Defualt. \n"); 
2342                }                       
2343               
2344                //we only free the crossbar when we close or restart the device
2345                //we were getting a crash otherwise
2346            //if(Crossbar)Crossbar->Release();
2347                //if(Crossbar)Crossbar = NULL;
2348                       
2349                if(pXBar1)pXBar1->Release();
2350                if(pXBar1)pXBar1 = NULL;
2351               
2352        }else{
2353                if(verbose)printf("SETUP: You are a webcam or snazzy firewire cam! No Crossbar needed\n");
2354                return hr;
2355        }
2356       
2357        return hr;
2358}
2359   
Note: See TracBrowser for help on using the repository browser.