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