Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2525 - 1
//*****************************************************************************************
2
//  File:       WebCamLib.cpp
3
//  Project:    WebcamLib
4
//  Author(s):  John Conwell
5
//              Gary Caldwell
6
//
7
//  Defines the webcam DirectShow wrapper used by TouchlessLib
8
//*****************************************************************************************
9
 
10
#include <dshow.h>
11
#include <strsafe.h>
12
#define __IDxtCompositor_INTERFACE_DEFINED__
13
#define __IDxtAlphaSetter_INTERFACE_DEFINED__
14
#define __IDxtJpeg_INTERFACE_DEFINED__
15
#define __IDxtKey_INTERFACE_DEFINED__
16
 
17
#pragma include_alias( "dxtrans.h", "qedit.h" )
18
 
19
#include "qedit.h"
20
#include "WebCamLib.h"
21
 
22
using namespace System;
23
using namespace System::Reflection;
24
using namespace WebCamLib;
25
 
26
 
27
// Private variables
28
#define MAX_CAMERAS 10
29
 
30
#pragma region CameraInfo Items
31
CameraInfo::CameraInfo( int index, String^ name )
32
{
33
        Index = index;
34
        Name = name;
35
}
36
 
37
int CameraInfo::Index::get()
38
{
39
        return index;
40
}
41
 
42
void CameraInfo::Index::set( int value )
43
{
44
        index = value;
45
}
46
 
47
String^ CameraInfo::Name::get()
48
{
49
        return name;
50
}
51
 
52
void CameraInfo::Name::set( String^ value )
53
{
54
        if( value != nullptr )
55
                name = value;
56
        else
57
                throw gcnew ArgumentNullException( "Name cannot be null." );
58
}
59
#pragma endregion
60
 
61
#pragma region CameraPropertyCapabilities Items
62
CameraPropertyCapabilities::CameraPropertyCapabilities( int cameraIndex, CameraProperty prop, bool isGetSupported, bool isSetSupported, bool isGetRangeSupported )
63
{
64
        CameraIndex = cameraIndex;
65
        Property = prop;
66
        IsGetSupported = isGetSupported;
67
        IsSetSupported = isSetSupported;
68
        IsGetRangeSupported = isGetRangeSupported;
69
}
70
 
71
int CameraPropertyCapabilities::CameraIndex::get()
72
{
73
        return cameraIndex;
74
}
75
 
76
void CameraPropertyCapabilities::CameraIndex::set( int value )
77
{
78
        cameraIndex =value;
79
}
80
 
81
CameraProperty CameraPropertyCapabilities::Property::get()
82
{
83
        return prop;
84
}
85
 
86
void CameraPropertyCapabilities::Property::set( CameraProperty value )
87
{
88
        prop = value;
89
}
90
 
91
bool CameraPropertyCapabilities::IsGetSupported::get()
92
{
93
        return isGetSupported;
94
}
95
 
96
void CameraPropertyCapabilities::IsGetSupported::set( bool value )
97
{
98
        isGetSupported = value;
99
}
100
 
101
bool CameraPropertyCapabilities::IsSetSupported::get()
102
{
103
        return isSetSupported;
104
}
105
 
106
void CameraPropertyCapabilities::IsSetSupported::set( bool value )
107
{
108
        isSetSupported = value;
109
}
110
 
111
bool CameraPropertyCapabilities::IsGetRangeSupported::get()
112
{
113
        return isGetRangeSupported;
114
}
115
 
116
void CameraPropertyCapabilities::IsGetRangeSupported::set( bool value )
117
{
118
        isGetRangeSupported = value;
119
}
120
 
121
bool CameraPropertyCapabilities::IsSupported::get()
122
{
123
        return IsGetSupported || IsSetSupported || IsGetRangeSupported;
124
}
125
 
126
bool CameraPropertyCapabilities::IsFullySupported::get()
127
{
128
        return IsGetSupported && IsSetSupported && IsGetRangeSupported;
129
}
130
#pragma endregion
131
 
132
// Structure to hold camera information
133
struct CameraInfoStruct
134
{
135
        BSTR bstrName;
136
        IMoniker* pMoniker;
137
};
138
 
139
 
140
// Private global variables
141
IGraphBuilder* g_pGraphBuilder = NULL;
142
IMediaControl* g_pMediaControl = NULL;
143
ICaptureGraphBuilder2* g_pCaptureGraphBuilder = NULL;
144
IBaseFilter* g_pIBaseFilterCam = NULL;
145
IBaseFilter* g_pIBaseFilterSampleGrabber = NULL;
146
IBaseFilter* g_pIBaseFilterNullRenderer = NULL;
147
CameraInfoStruct g_aCameraInfo[MAX_CAMERAS] = {0};
148
IMediaSeeking *m_pMediaSeek = NULL;
149
 
150
// http://social.msdn.microsoft.com/Forums/sk/windowsdirectshowdevelopment/thread/052d6a15-f092-4913-b52d-d28f9a51e3b6
151
void MyFreeMediaType(AM_MEDIA_TYPE& mt) {
152
        if (mt.cbFormat != 0) {
153
                CoTaskMemFree((PVOID)mt.pbFormat);
154
                mt.cbFormat = 0;
155
                mt.pbFormat = NULL;
156
        }
157
        if (mt.pUnk != NULL) {
158
                // Unecessary because pUnk should not be used, but safest.
159
                mt.pUnk->Release();
160
                mt.pUnk = NULL;
161
        }
162
}
163
void MyDeleteMediaType(AM_MEDIA_TYPE *pmt) {
164
        if (pmt != NULL) {
165
                MyFreeMediaType(*pmt); // See FreeMediaType for the implementation.
166
                CoTaskMemFree(pmt);
167
        }
168
}
169
 
170
 
171
/// <summary>
172
/// Initializes information about all web cams connected to machine
173
/// </summary>
174
CameraMethods::CameraMethods()
175
{
176
        // Set to not disposed
177
        this->disposed = false;
178
 
179
        // Get and cache camera info
180
        RefreshCameraList();
181
}
182
 
183
/// <summary>
184
/// IDispose
185
/// </summary>
186
CameraMethods::~CameraMethods()
187
{
188
        Cleanup();
189
        disposed = true;
190
}
191
 
192
/// <summary>
193
/// Finalizer
194
/// </summary>
195
CameraMethods::!CameraMethods()
196
{
197
        if (!disposed)
198
        {
199
                Cleanup();
200
        }
201
}
202
 
203
/// <summary>
204
/// Initialize information about webcams installed on machine
205
/// </summary>
206
void CameraMethods::RefreshCameraList()
207
{
208
        IEnumMoniker* pclassEnum = NULL;
209
        ICreateDevEnum* pdevEnum = NULL;
210
 
211
        int count = 0;
212
 
213
        CleanupCameraInfo();
214
 
215
        HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum,
216
                NULL,
217
                CLSCTX_INPROC,
218
                IID_ICreateDevEnum,
219
                (LPVOID*)&pdevEnum);
220
 
221
        if (SUCCEEDED(hr))
222
        {
223
                hr = pdevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pclassEnum, 0);
224
        }
225
 
226
        if (pdevEnum != NULL)
227
        {
228
                pdevEnum->Release();
229
                pdevEnum = NULL;
230
        }
231
 
232
        if (pclassEnum != NULL)
233
        {
234
                IMoniker* apIMoniker[1];
235
                ULONG ulCount = 0;
236
 
237
                while (SUCCEEDED(hr) && (count) < MAX_CAMERAS && pclassEnum->Next(1, apIMoniker, &ulCount) == S_OK)
238
                {
239
                        g_aCameraInfo[count].pMoniker = apIMoniker[0];
240
                        g_aCameraInfo[count].pMoniker->AddRef();
241
 
242
                        IPropertyBag *pPropBag;
243
                        hr = apIMoniker[0]->BindToStorage(NULL, NULL, IID_IPropertyBag, (void **)&pPropBag);
244
                        if (SUCCEEDED(hr))
245
                        {
246
                                // Retrieve the filter's friendly name
247
                                VARIANT varName;
248
                                VariantInit(&varName);
249
                                hr = pPropBag->Read(L"FriendlyName", &varName, 0);
250
                                if (SUCCEEDED(hr) && varName.vt == VT_BSTR)
251
                                {
252
                                        g_aCameraInfo[count].bstrName = SysAllocString(varName.bstrVal);
253
                                }
254
                                VariantClear(&varName);
255
 
256
                                pPropBag->Release();
257
                        }
258
 
259
                        count++;
260
                }
261
 
262
                pclassEnum->Release();
263
        }
264
 
265
        this->Count = count;
266
 
267
        if (!SUCCEEDED(hr))
268
                throw gcnew COMException("Error Refreshing Camera List", hr);
269
}
270
 
271
/// <summary>
272
/// Retrieve information about a specific camera
273
/// Use the count property to determine valid indicies to pass in
274
/// </summary>
275
CameraInfo^ CameraMethods::GetCameraInfo(int camIndex)
276
{
277
        if (camIndex >= Count)
278
                throw gcnew ArgumentOutOfRangeException("Camera index is out of bounds: " + Count.ToString());
279
 
280
        if (g_aCameraInfo[camIndex].pMoniker == NULL)
281
                throw gcnew ArgumentException("There is no camera at index: " + camIndex.ToString());
282
 
283
        CameraInfo^ camInfo = gcnew CameraInfo( camIndex, Marshal::PtrToStringBSTR((IntPtr)g_aCameraInfo[camIndex].bstrName) );
284
 
285
        return camInfo;
286
}
287
 
288
/// <summary>
289
/// Start the camera associated with the input handle
290
/// </summary>
291
void CameraMethods::StartCamera(int camIndex, interior_ptr<int> width, interior_ptr<int> height, interior_ptr<int> bpp, interior_ptr<bool> successful)
292
{
293
        *successful = StartCamera( camIndex, width, height, bpp );
294
}
295
 
296
/// <summary>
297
/// Start the camera associated with the input handle
298
/// </summary>
299
bool CameraMethods::StartCamera(int camIndex, interior_ptr<int> width, interior_ptr<int> height, interior_ptr<int> bpp)
300
{
301
        if (camIndex >= Count)
302
                throw gcnew ArgumentException("Camera index is out of bounds: " + Count.ToString());
303
 
304
        if (g_aCameraInfo[camIndex].pMoniker == NULL)
305
                throw gcnew ArgumentException("There is no camera at index: " + camIndex.ToString());
306
 
307
        if (g_pGraphBuilder != NULL)
308
                throw gcnew ArgumentException("Graph Builder was null");
309
 
310
        // Setup up function callback -- through evil reflection on private members
311
        Type^ baseType = this->GetType();
312
        FieldInfo^ field = baseType->GetField("<backing_store>OnImageCapture", BindingFlags::NonPublic | BindingFlags::Instance | BindingFlags::IgnoreCase);
313
        if (field != nullptr)
314
        {
315
                Object^ obj = field->GetValue(this);
316
                if (obj != nullptr)
317
                {
318
                        CameraMethods::CaptureCallbackDelegate^ del = (CameraMethods::CaptureCallbackDelegate^)field->GetValue(this);
319
                        if (del != nullptr)
320
                        {
321
                                ppCaptureCallback = GCHandle::Alloc(del);
322
                                g_pfnCaptureCallback =
323
                                        static_cast<PFN_CaptureCallback>(Marshal::GetFunctionPointerForDelegate(del).ToPointer());
324
                        }
325
                }
326
        }
327
 
328
        bool result = false;
329
 
330
        IMoniker *pMoniker = g_aCameraInfo[camIndex].pMoniker;
331
        pMoniker->AddRef();
332
 
333
        HRESULT hr = S_OK;
334
 
335
        // Build all the necessary interfaces to start the capture
336
        if (SUCCEEDED(hr))
337
        {
338
                hr = CoCreateInstance(CLSID_FilterGraph,
339
                        NULL,
340
                        CLSCTX_INPROC,
341
                        IID_IGraphBuilder,
342
                        (LPVOID*)&g_pGraphBuilder);
343
        }
344
 
345
        if (SUCCEEDED(hr))
346
        {
347
                hr = g_pGraphBuilder->QueryInterface(IID_IMediaControl, (LPVOID*)&g_pMediaControl);
348
        }
349
 
350
        if (SUCCEEDED(hr))
351
        {
352
                hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
353
                        NULL,
354
                        CLSCTX_INPROC,
355
                        IID_ICaptureGraphBuilder2,
356
                        (LPVOID*)&g_pCaptureGraphBuilder);
357
        }
358
 
359
        // Setup the filter graph
360
        if (SUCCEEDED(hr))
361
        {
362
                hr = g_pCaptureGraphBuilder->SetFiltergraph(g_pGraphBuilder);
363
        }
364
 
365
        // Build the camera from the moniker
366
        if (SUCCEEDED(hr))
367
        {
368
                hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (LPVOID*)&g_pIBaseFilterCam);
369
        }
370
 
371
        // Add the camera to the filter graph
372
        if (SUCCEEDED(hr))
373
        {
374
                hr = g_pGraphBuilder->AddFilter(g_pIBaseFilterCam, L"WebCam");
375
        }
376
 
377
        // Set the resolution
378
        if (SUCCEEDED(hr)) {
379
                hr = SetCaptureFormat(g_pIBaseFilterCam, *width, *height, *bpp);
380
        }
381
 
382
        // Create a SampleGrabber
383
        if (SUCCEEDED(hr))
384
        {
385
                hr = CoCreateInstance(CLSID_SampleGrabber, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&g_pIBaseFilterSampleGrabber);
386
        }
387
 
388
        // Configure the Sample Grabber
389
        if (SUCCEEDED(hr))
390
        {
391
                hr = ConfigureSampleGrabber(g_pIBaseFilterSampleGrabber);
392
        }
393
 
394
        // Add Sample Grabber to the filter graph
395
        if (SUCCEEDED(hr))
396
        {
397
                hr = g_pGraphBuilder->AddFilter(g_pIBaseFilterSampleGrabber, L"SampleGrabber");
398
        }
399
 
400
        // Create the NullRender
401
        if (SUCCEEDED(hr))
402
        {
403
                hr = CoCreateInstance(CLSID_NullRenderer, NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&g_pIBaseFilterNullRenderer);
404
        }
405
 
406
        // Add the Null Render to the filter graph
407
        if (SUCCEEDED(hr))
408
        {
409
                hr = g_pGraphBuilder->AddFilter(g_pIBaseFilterNullRenderer, L"NullRenderer");
410
        }
411
 
412
        // Configure the render stream
413
        if (SUCCEEDED(hr))
414
        {
415
                hr = g_pCaptureGraphBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, g_pIBaseFilterCam, g_pIBaseFilterSampleGrabber, g_pIBaseFilterNullRenderer);
416
        }
417
 
418
        // Grab the capture width and height
419
        if (SUCCEEDED(hr))
420
        {
421
                ISampleGrabber* pGrabber = NULL;
422
                hr = g_pIBaseFilterSampleGrabber->QueryInterface(IID_ISampleGrabber, (LPVOID*)&pGrabber);
423
                if (SUCCEEDED(hr))
424
                {
425
                        AM_MEDIA_TYPE mt;
426
                        hr = pGrabber->GetConnectedMediaType(&mt);
427
                        if (SUCCEEDED(hr))
428
                        {
429
                                VIDEOINFOHEADER *pVih;
430
                                if ((mt.formattype == FORMAT_VideoInfo) &&
431
                                        (mt.cbFormat >= sizeof(VIDEOINFOHEADER)) &&
432
                                        (mt.pbFormat != NULL) )
433
                                {
434
                                        pVih = (VIDEOINFOHEADER*)mt.pbFormat;
435
                                        *width = pVih->bmiHeader.biWidth;
436
                                        *height = pVih->bmiHeader.biHeight;
437
                                        *bpp = pVih->bmiHeader.biBitCount;
438
                                }
439
                                else
440
                                {
441
                                        hr = E_FAIL;  // Wrong format
442
                                }
443
 
444
                                // FreeMediaType(mt); (from MSDN)
445
                                if (mt.cbFormat != 0)
446
                                {
447
                                        CoTaskMemFree((PVOID)mt.pbFormat);
448
                                        mt.cbFormat = 0;
449
                                        mt.pbFormat = NULL;
450
                                }
451
                                if (mt.pUnk != NULL)
452
                                {
453
                                        // Unecessary because pUnk should not be used, but safest.
454
                                        mt.pUnk->Release();
455
                                        mt.pUnk = NULL;
456
                                }
457
                        }
458
                }
459
 
460
                if (pGrabber != NULL)
461
                {
462
                        pGrabber->Release();
463
                        pGrabber = NULL;
464
                }
465
        }
466
 
467
        // Start the capture
468
        if (SUCCEEDED(hr))
469
        {
470
                hr = g_pMediaControl->Run();
471
        }
472
 
473
        // If init fails then ensure that you cleanup
474
        if (FAILED(hr))
475
        {
476
                StopCamera();
477
        }
478
        else
479
        {
480
                hr = S_OK;  // Make sure we return S_OK for success
481
        }
482
 
483
        // Cleanup
484
        if (pMoniker != NULL)
485
        {
486
                pMoniker->Release();
487
                pMoniker = NULL;
488
        }
489
 
490
        if( result = SUCCEEDED( hr ) )
491
                this->activeCameraIndex = camIndex;
492
 
493
        return result;
494
}
495
 
496
#pragma region Camera Property Support
497
inline void CameraMethods::IsPropertySupported( CameraProperty prop, interior_ptr<bool> result )
498
{
499
        *result = IsPropertySupported( prop );
500
}
501
 
502
inline bool CameraMethods::IsPropertySupported( CameraProperty prop )
503
{
504
        bool result = false;
505
 
506
        if( IsCameraControlProperty( prop ) )
507
                result = IsPropertySupported( GetCameraControlProperty( prop ) );
508
        else if( IsVideoProcAmpProperty( prop ) )
509
                result = IsPropertySupported( GetVideoProcAmpProperty( prop ) );
510
 
511
        return result;
512
}
513
 
514
bool CameraMethods::IsPropertySupported( WebCamLib::CameraControlProperty prop )
515
{
516
        bool result = false;
517
 
518
        IAMCameraControl * cameraControl = NULL;
519
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMCameraControl, (void**)&cameraControl);
520
 
521
        if(SUCCEEDED(hr))
522
        {
523
                long lProperty = static_cast< long >( prop );
524
                long value, captureFlags;
525
                hr = cameraControl->Get(lProperty, &value, &captureFlags);
526
 
527
                result = SUCCEEDED(hr);
528
        }
529
        //else
530
        //      throw gcnew InvalidOperationException( "Unable to determine if the property is supported." );
531
 
532
        return result;
533
}
534
 
535
bool CameraMethods::IsPropertySupported( WebCamLib::VideoProcAmpProperty prop )
536
{
537
        bool result = false;
538
 
539
        IAMVideoProcAmp * pProcAmp = NULL;
540
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
541
 
542
        if(SUCCEEDED(hr))
543
        {
544
                long lProperty = static_cast< long >( prop );
545
                long value, captureFlags;
546
                hr = pProcAmp->Get(lProperty, &value, &captureFlags);
547
 
548
                result = SUCCEEDED(hr);
549
        }
550
        else
551
                throw gcnew InvalidOperationException( "Unable to determine if the property is supported." );
552
 
553
        return result;
554
}
555
 
556
inline bool CameraMethods::IsCameraControlProperty( CameraProperty prop )
557
{
558
        return IsPropertyMaskEqual( prop, PropertyTypeMask::CameraControlPropertyMask );
559
}
560
 
561
inline bool CameraMethods::IsVideoProcAmpProperty( CameraProperty prop )
562
{
563
        return IsPropertyMaskEqual( prop, PropertyTypeMask::VideoProcAmpPropertyMask );
564
}
565
 
566
inline bool CameraMethods::IsPropertyMaskEqual( CameraProperty prop, PropertyTypeMask mask )
567
{
568
        return ( static_cast< int >( prop ) & static_cast< int >( mask ) ) != 0;
569
}
570
 
571
inline void CameraMethods::GetProperty( CameraProperty prop, bool isValue, interior_ptr<long> value, interior_ptr<bool> bAuto, interior_ptr<bool> successful )
572
{
573
        *successful = GetProperty( prop, isValue, value, bAuto );
574
}
575
 
576
inline bool CameraMethods::GetProperty( CameraProperty prop, bool isValue, interior_ptr<long> value, interior_ptr<bool> bAuto )
577
{
578
        bool result;
579
 
580
        if( isValue )
581
                result = GetProperty_value( prop, value, bAuto );
582
        else // is a percentage value
583
                result = GetProperty_percentage( prop, value, bAuto );
584
 
585
        return result;
586
}
587
 
588
inline WebCamLib::CameraControlProperty CameraMethods::GetCameraControlProperty( CameraProperty prop )
589
{
590
        if( IsCameraControlProperty( prop ) )
591
        {
592
                int value = static_cast< int >( prop );
593
                int mask = static_cast< int >( PropertyTypeMask::CameraControlPropertyMask );
594
                value &= ~mask;
595
 
596
                return static_cast< WebCamLib::CameraControlProperty >( value );
597
        }
598
        else
599
                throw gcnew OverflowException( "Property is not a camera property." );
600
}
601
 
602
inline WebCamLib::VideoProcAmpProperty CameraMethods::GetVideoProcAmpProperty( CameraProperty prop )
603
{
604
        if( IsVideoProcAmpProperty( prop ) )
605
        {
606
                int value = static_cast< int >( prop );
607
                int mask = static_cast< int >( PropertyTypeMask::VideoProcAmpPropertyMask );
608
                value &= ~mask;
609
 
610
                return static_cast< WebCamLib::VideoProcAmpProperty >( value );
611
        }
612
        else
613
                throw gcnew OverflowException( "Property is not a camera property." );
614
}
615
 
616
inline void CameraMethods::GetProperty_value( CameraProperty prop, interior_ptr<long> value, interior_ptr<bool> bAuto, interior_ptr<bool> successful)
617
{
618
        *successful = GetProperty_value( prop, value, bAuto );
619
}
620
 
621
inline bool CameraMethods::GetProperty_value( CameraProperty prop, interior_ptr<long> value, interior_ptr<bool> bAuto)
622
{
623
        bool result = false;
624
 
625
        if( IsCameraControlProperty( prop ) )
626
                result = GetProperty_value( GetCameraControlProperty( prop ), value, bAuto );
627
        else if( IsVideoProcAmpProperty( prop ) )
628
                result = GetProperty_value( GetVideoProcAmpProperty( prop ), value, bAuto );
629
 
630
        return result;
631
}
632
 
633
inline void CameraMethods::GetProperty_percentage( CameraProperty prop, interior_ptr<long> percentage, interior_ptr<bool> bAuto, interior_ptr<bool> successful)
634
{
635
        *successful = GetProperty_percentage( prop, percentage, bAuto );
636
}
637
 
638
bool CameraMethods::GetProperty_percentage( CameraProperty prop, interior_ptr<long> percentage, interior_ptr<bool> bAuto)
639
{
640
        bool result;
641
 
642
        long value;
643
        if( result = GetProperty_value( prop, &value, bAuto ) )
644
        {
645
                long min, max, steppingDelta, defaults;
646
                bool placeHolder;
647
                if( result = GetPropertyRange( prop, &min, &max, &steppingDelta, &defaults, &placeHolder ) )
648
                        *percentage = ( ( value - min ) * 100 ) / ( max - min + 1 );
649
        }
650
 
651
        return result;
652
}
653
 
654
inline void CameraMethods::SetProperty( CameraProperty prop, bool isValue, long value, bool bAuto, interior_ptr<bool> successful )
655
{
656
        *successful = SetProperty( prop, isValue, value, bAuto );
657
}
658
 
659
inline bool CameraMethods::SetProperty( CameraProperty prop, bool isValue, long value, bool bAuto )
660
{
661
        bool result;
662
 
663
        if( isValue )
664
                result = SetProperty_value( prop, value, bAuto );
665
        else  // is a percentage value
666
                result = SetProperty_percentage( prop, value, bAuto );
667
 
668
        return result;
669
}
670
 
671
inline void CameraMethods::SetProperty_value(CameraProperty prop, long value, bool bAuto, interior_ptr<bool> successful)
672
{
673
        *successful = SetProperty_value( prop, value, bAuto );
674
}
675
 
676
inline bool CameraMethods::SetProperty_value(CameraProperty prop, long value, bool bAuto)
677
{
678
        return SetProperty_value( prop, value, bAuto, true );
679
}
680
 
681
inline void CameraMethods::SetProperty_value( CameraProperty prop, long value, bool bAuto, bool throwValidationError, interior_ptr<bool> successful )
682
{
683
        *successful = SetProperty_value( prop, value, bAuto, throwValidationError );
684
}
685
 
686
inline bool CameraMethods::SetProperty_value( CameraProperty prop, long value, bool bAuto, bool throwValidationError )
687
{
688
        bool result = false;
689
 
690
        if( ValidatePropertyValue( prop, value ) )
691
        {
692
                if( IsCameraControlProperty( prop ) )
693
                        result = SetProperty_value( GetCameraControlProperty( prop ), value, bAuto );
694
                else if( IsVideoProcAmpProperty( prop ) )
695
                        result = SetProperty_value( GetVideoProcAmpProperty( prop ), value, bAuto );
696
        }
697
        else if( throwValidationError )
698
                throw gcnew ArgumentOutOfRangeException( "Property value is outside of its defined range." );
699
 
700
        return result;
701
}
702
 
703
inline void CameraMethods::SetProperty_percentage(CameraProperty prop, long percentage, bool bAuto, interior_ptr<bool> successful)
704
{
705
        *successful = SetProperty_percentage( prop, percentage, bAuto );
706
}
707
 
708
bool CameraMethods::SetProperty_percentage(CameraProperty prop, long percentage, bool bAuto)
709
{
710
        if( !IsPropertySupported( prop ) )
711
                throw gcnew ArgumentException( "Property is not supported." );
712
        else if( percentage >= 0 && percentage <= 100 )
713
        {
714
                bool result;
715
 
716
                long min, max, steppingDelta, defaults;
717
                bool placeHolder;
718
                if( result = GetPropertyRange( prop, &min, &max, &steppingDelta, &defaults, &placeHolder ) )
719
                {
720
                        long value = ( ( max - min ) * percentage ) / 100 + min;
721
                        result = SetProperty_value( prop, value, bAuto );
722
                }
723
 
724
                return result;
725
        }
726
        else
727
                throw gcnew ArgumentOutOfRangeException( "Percentage is not valid." );
728
}
729
 
730
inline void CameraMethods::GetPropertyRange( CameraProperty prop, interior_ptr<long> min, interior_ptr<long> max, interior_ptr<long> steppingDelta, interior_ptr<long> defaults, interior_ptr<bool> bAuto, interior_ptr<bool> successful)
731
{
732
        *successful = GetPropertyRange( prop, min, max, steppingDelta, defaults, bAuto );
733
}
734
 
735
inline bool CameraMethods::GetPropertyRange( CameraProperty prop, interior_ptr<long> min, interior_ptr<long> max, interior_ptr<long> steppingDelta, interior_ptr<long> defaults, interior_ptr<bool> bAuto)
736
{
737
        bool result = false;
738
 
739
        if( IsCameraControlProperty( prop ) )
740
                result = GetPropertyRange( GetCameraControlProperty( prop ), min, max, steppingDelta, defaults, bAuto );
741
        else if( IsVideoProcAmpProperty( prop ) )
742
                result = GetPropertyRange( GetVideoProcAmpProperty( prop ), min, max, steppingDelta, defaults, bAuto );
743
 
744
        return result;
745
}
746
 
747
bool CameraMethods::GetPropertyRange( WebCamLib::CameraControlProperty prop, interior_ptr<long> min, interior_ptr<long> max, interior_ptr<long> steppingDelta, interior_ptr<long> defaults, interior_ptr<bool> bAuto )
748
{
749
        bool result = false;
750
 
751
        IAMCameraControl * cameraControl = NULL;
752
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMCameraControl, (void**)&cameraControl);
753
 
754
        if( SUCCEEDED( hr ) )
755
        {
756
                long lProperty = static_cast< long >( prop );
757
                long minimum, maximum, step, default_value, flags;
758
                hr = cameraControl->GetRange( lProperty, &minimum, &maximum, &step, &default_value, &flags );
759
 
760
                if( SUCCEEDED( hr ) )
761
                {
762
                        *min = minimum;
763
                        *max = maximum;
764
                        *steppingDelta = step;
765
                        *defaults = default_value;
766
                        *bAuto = flags == CameraControl_Flags_Auto;
767
 
768
                        result = SUCCEEDED(hr);
769
                }
770
        }
771
 
772
        return result;
773
}
774
 
775
bool CameraMethods::GetPropertyRange( WebCamLib::VideoProcAmpProperty prop, interior_ptr<long> min, interior_ptr<long> max, interior_ptr<long> steppingDelta, interior_ptr<long> defaults, interior_ptr<bool> bAuto )
776
{
777
        bool result = false;
778
 
779
        IAMVideoProcAmp * pProcAmp = NULL;
780
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
781
 
782
        if( SUCCEEDED( hr ) )
783
        {
784
                long lProperty = static_cast< long >( prop );
785
                long minimum, maximum, step, default_value, flags;
786
                hr = pProcAmp->GetRange( lProperty, &minimum, &maximum, &step, &default_value, &flags );
787
 
788
                if( SUCCEEDED( hr ) )
789
                {
790
                        *min = minimum;
791
                        *max = maximum;
792
                        *steppingDelta = step;
793
                        *defaults = default_value;
794
                        *bAuto = flags == CameraControl_Flags_Auto;
795
 
796
                        result = SUCCEEDED(hr);
797
                }
798
        }
799
 
800
        return result;
801
}
802
 
803
bool CameraMethods::GetProperty_value( WebCamLib::CameraControlProperty prop, interior_ptr<long> value, interior_ptr<bool> bAuto )
804
{
805
        if( g_pIBaseFilterCam == NULL )
806
                throw gcnew InvalidOperationException( "No camera started." );
807
 
808
        bool result = false;
809
 
810
        IAMCameraControl * cameraControl = NULL;
811
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMCameraControl, (void**)&cameraControl);
812
 
813
        if( SUCCEEDED( hr ) )
814
        {
815
                long lProperty = static_cast< long >( prop );
816
                long lValue, captureFlags;
817
                hr = cameraControl->Get(lProperty, &lValue, &captureFlags);
818
 
819
                if( result = SUCCEEDED( hr ) )
820
                {
821
                        *value = lValue;
822
                        *bAuto = captureFlags == CameraControl_Flags_Auto;
823
                }
824
        }
825
 
826
        return result;
827
}
828
 
829
bool CameraMethods::GetProperty_value( WebCamLib::VideoProcAmpProperty prop, interior_ptr<long> value, interior_ptr<bool> bAuto )
830
{
831
        if( g_pIBaseFilterCam == NULL )
832
                throw gcnew InvalidOperationException( "No camera started." );
833
 
834
        bool result = false;
835
 
836
        IAMVideoProcAmp * pProcAmp = NULL;
837
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
838
 
839
        if( SUCCEEDED( hr ) )
840
        {
841
                long lProperty = static_cast< long >( prop );
842
                long lValue, captureFlags;
843
                hr = pProcAmp->Get(lProperty, &lValue, &captureFlags);
844
 
845
                if( result = SUCCEEDED( hr ) )
846
                {
847
                        *value = lValue;
848
                        *bAuto = captureFlags == VideoProcAmp_Flags_Auto;
849
                }
850
        }
851
 
852
        return result;
853
}
854
 
855
bool CameraMethods::SetProperty_value( WebCamLib::CameraControlProperty prop, long value, bool bAuto )
856
{
857
        if( g_pIBaseFilterCam == NULL )
858
                throw gcnew InvalidOperationException( "No camera started." );
859
 
860
        bool result = false;
861
 
862
        // Query the capture filter for the IAMCameraControl interface.
863
        IAMCameraControl * cameraControl = NULL;
864
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMCameraControl, (void**)&cameraControl);
865
 
866
        if( SUCCEEDED( hr ) )
867
        {
868
                long lProperty = static_cast< long >( prop );
869
                hr = cameraControl->Set(lProperty, value, bAuto ? CameraControl_Flags_Auto : CameraControl_Flags_Manual);
870
 
871
                result = SUCCEEDED( hr );
872
        }
873
 
874
        return result;
875
}
876
 
877
bool CameraMethods::SetProperty_value( WebCamLib::VideoProcAmpProperty prop, long value, bool bAuto )
878
{
879
        if( g_pIBaseFilterCam == NULL )
880
                throw gcnew InvalidOperationException( "No camera started." );
881
 
882
        bool result = false;
883
 
884
        // Query the capture filter for the IAMVideoProcAmp interface.
885
        IAMVideoProcAmp * pProcAmp = NULL;
886
        HRESULT hr = g_pIBaseFilterCam->QueryInterface(IID_IAMVideoProcAmp, (void**)&pProcAmp);
887
 
888
        if( SUCCEEDED( hr ) )
889
        {
890
                long lProperty = static_cast< long >( prop );
891
                hr = pProcAmp->Set(lProperty, value, bAuto ? VideoProcAmp_Flags_Auto : VideoProcAmp_Flags_Manual);
892
 
893
                result = SUCCEEDED( hr );
894
        }
895
 
896
        return result;
897
}
898
 
899
void CameraMethods::PropertyHasRange( CameraProperty prop, interior_ptr<bool> successful )
900
{
901
        *successful = PropertyHasRange( prop );
902
}
903
 
904
bool CameraMethods::PropertyHasRange( CameraProperty prop )
905
{
906
        bool result = prop != CameraProperty::WhiteBalance && prop != CameraProperty::Gain;
907
 
908
        return result;
909
}
910
 
911
inline void CameraMethods::ValidatePropertyValue( CameraProperty prop, long value, interior_ptr<bool> successful )
912
{
913
        *successful = ValidatePropertyValue( prop, value );
914
}
915
 
916
bool CameraMethods::ValidatePropertyValue( CameraProperty prop, long value )
917
{
918
        bool result = true;
919
 
920
        if( PropertyHasRange( prop ) )
921
        {
922
                long min, max, steppingDelta, defaults;
923
                bool bAuto;
924
                GetPropertyRange( prop, &min, &max, &steppingDelta, &defaults, &bAuto );
925
 
926
                result = value >= min && value <= max;
927
        }
928
 
929
        return result;
930
}
931
 
932
CameraPropertyCapabilities^ CameraMethods::GetPropertyCapability( CameraProperty prop )
933
{
934
        long value;
935
        bool isAuto;
936
 
937
        bool propertyHasRange = PropertyHasRange( prop );
938
        bool isSetSupported;
939
        bool isGetSupported = GetProperty_value( prop, &value, &isAuto );
940
        if( isGetSupported )
941
                isSetSupported = SetProperty_value( prop, value, isAuto );
942
        else
943
                isSetSupported = false;
944
 
945
        CameraPropertyCapabilities^ result = gcnew CameraPropertyCapabilities( ActiveCameraIndex, prop, isGetSupported, isSetSupported, propertyHasRange );
946
 
947
        return result;
948
}
949
 
950
IDictionary<CameraProperty, CameraPropertyCapabilities^> ^ CameraMethods::PropertyCapabilities::get()
951
{
952
        Array^ propertyValues = Enum::GetValues( CameraProperty::typeid );
953
 
954
        IDictionary<CameraProperty, CameraPropertyCapabilities^> ^ result = gcnew Dictionary<CameraProperty, CameraPropertyCapabilities^>( propertyValues->Length );
955
 
956
        for( Int32 i = 0; i < propertyValues->Length; ++i )
957
        {
958
                CameraProperty prop = static_cast<CameraProperty>( propertyValues->GetValue( i ) );
959
                result->Add( prop, GetPropertyCapability( prop ) );
960
        }
961
 
962
        return result;
963
}
964
#pragma endregion
965
 
966
/// <summary>
967
/// Closes any open webcam and releases all unmanaged resources
968
/// </summary>
969
void CameraMethods::Cleanup()
970
{
971
        StopCamera();
972
        CleanupCameraInfo();
973
 
974
        // Clean up pinned pointer to callback delegate
975
        if (ppCaptureCallback.IsAllocated)
976
        {
977
                ppCaptureCallback.Free();
978
        }
979
}
980
 
981
/// <summary>
982
/// Stops the current open webcam
983
/// </summary>
984
void CameraMethods::StopCamera()
985
{
986
        //HRESULT hr = g_pGraphBuilder->QueryInterface(IID_IMediaSeeking, (void**)&m_pMediaSeek);
987
 
988
        g_pfnCaptureCallback = NULL;
989
 
990
        if (g_pIBaseFilterNullRenderer != NULL)
991
        {
992
                g_pIBaseFilterNullRenderer->Release();
993
                g_pIBaseFilterNullRenderer = NULL;
994
        }
995
 
996
        if (g_pIBaseFilterSampleGrabber != NULL)
997
        {
998
                g_pIBaseFilterSampleGrabber->Release();
999
                g_pIBaseFilterSampleGrabber = NULL;
1000
        }
1001
 
1002
        if (g_pIBaseFilterCam != NULL)
1003
        {
1004
                g_pIBaseFilterCam->Release();
1005
                g_pIBaseFilterCam = NULL;
1006
        }
1007
 
1008
        if (g_pGraphBuilder != NULL)
1009
        {
1010
                g_pGraphBuilder->Release();
1011
                g_pGraphBuilder = NULL;
1012
        }
1013
 
1014
        if (g_pCaptureGraphBuilder != NULL)
1015
        {
1016
                g_pCaptureGraphBuilder->Release();
1017
                g_pCaptureGraphBuilder = NULL;
1018
        }
1019
        if (g_pMediaControl != NULL)
1020
        {
1021
 
1022
                g_pMediaControl->Pause();
1023
                //try
1024
                //{
1025
                g_pMediaControl->GetState(1000, NULL);
1026
 
1027
        //      long long m_pStart = 0;
1028
        //      if (m_pMediaSeek != NULL)
1029
        //      {
1030
        //              m_pMediaSeek->SetPositions(&m_pStart, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
1031
        //      }
1032
        ////    g_pMediaControl->Run();
1033
        //      hr = g_pMediaControl->GetState(1000, NULL);
1034
                g_pMediaControl->Stop();
1035
        //      g_pMediaControl->GetState(1000, NULL);
1036
 
1037
                //}
1038
                //catch (const int e)
1039
                //{
1040
 
1041
                //}
1042
                //finally
1043
                {
1044
                        g_pMediaControl->Release();
1045
                        g_pMediaControl = NULL;
1046
                }
1047
        }
1048
 
1049
 
1050
        this->activeCameraIndex = -1;
1051
}
1052
 
1053
/// <summary>
1054
/// Show the properties dialog for the specified webcam
1055
/// </summary>
1056
void CameraMethods::DisplayCameraPropertiesDialog(int camIndex)
1057
{
1058
        if (camIndex >= Count)
1059
                throw gcnew ArgumentException("Camera index is out of bounds: " + Count.ToString());
1060
 
1061
        if (g_aCameraInfo[camIndex].pMoniker == NULL)
1062
                throw gcnew ArgumentException("There is no camera at index: " + camIndex.ToString());
1063
 
1064
        HRESULT hr = S_OK;
1065
        IBaseFilter *pFilter = NULL;
1066
        ISpecifyPropertyPages *pProp = NULL;
1067
        IMoniker *pMoniker = g_aCameraInfo[camIndex].pMoniker;
1068
        pMoniker->AddRef();
1069
 
1070
        // Create a filter graph for the moniker
1071
        if (SUCCEEDED(hr))
1072
        {
1073
                hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (LPVOID*)&pFilter);
1074
        }
1075
 
1076
        // See if it implements a property page
1077
        if (SUCCEEDED(hr))
1078
        {
1079
                hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (LPVOID*)&pProp);
1080
        }
1081
 
1082
        // Show the property page
1083
        if (SUCCEEDED(hr))
1084
        {
1085
                FILTER_INFO filterinfo;
1086
                hr = pFilter->QueryFilterInfo(&filterinfo);
1087
 
1088
                IUnknown *pFilterUnk = NULL;
1089
                if (SUCCEEDED(hr))
1090
                {
1091
                        hr = pFilter->QueryInterface(IID_IUnknown, (LPVOID*)&pFilterUnk);
1092
                }
1093
 
1094
                if (SUCCEEDED(hr))
1095
                {
1096
                        CAUUID caGUID;
1097
                        pProp->GetPages(&caGUID);
1098
 
1099
                        OleCreatePropertyFrame(
1100
                                NULL,                   // Parent window
1101
                                0, 0,                   // Reserved
1102
                                filterinfo.achName,     // Caption for the dialog box
1103
                                1,                      // Number of objects (just the filter)
1104
                                &pFilterUnk,            // Array of object pointers. 
1105
                                caGUID.cElems,          // Number of property pages
1106
                                caGUID.pElems,          // Array of property page CLSIDs
1107
                                0,                      // Locale identifier
1108
                                0, NULL                 // Reserved
1109
                                );
1110
                }
1111
 
1112
                if (pFilterUnk != NULL)
1113
                {
1114
                        pFilterUnk->Release();
1115
                        pFilterUnk = NULL;
1116
                }
1117
        }
1118
 
1119
        if (pProp != NULL)
1120
        {
1121
                pProp->Release();
1122
                pProp = NULL;
1123
        }
1124
 
1125
        if (pMoniker != NULL)
1126
        {
1127
                pMoniker->Release();
1128
                pMoniker = NULL;
1129
        }
1130
 
1131
        if (pFilter != NULL)
1132
        {
1133
                pFilter->Release();
1134
                pFilter = NULL;
1135
        }
1136
 
1137
        //if (!SUCCEEDED(hr))
1138
        //      throw gcnew COMException("Error displaying camera properties dialog", hr);
1139
}
1140
 
1141
/// <summary>
1142
/// Releases all unmanaged resources
1143
/// </summary>
1144
void CameraMethods::CleanupCameraInfo()
1145
{
1146
        for (int n = 0; n < MAX_CAMERAS; n++)
1147
        {
1148
                SysFreeString(g_aCameraInfo[n].bstrName);
1149
                g_aCameraInfo[n].bstrName = NULL;
1150
                if (g_aCameraInfo[n].pMoniker != NULL)
1151
                {
1152
                        g_aCameraInfo[n].pMoniker->Release();
1153
                        g_aCameraInfo[n].pMoniker = NULL;
1154
                }
1155
        }
1156
}
1157
 
1158
 
1159
/// <summary>
1160
/// Setup the callback functionality for DirectShow
1161
/// </summary>
1162
HRESULT CameraMethods::ConfigureSampleGrabber(IBaseFilter *pIBaseFilter)
1163
{
1164
        HRESULT hr = S_OK;
1165
 
1166
        ISampleGrabber *pGrabber = NULL;
1167
 
1168
        hr = pIBaseFilter->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);
1169
        if (SUCCEEDED(hr))
1170
        {
1171
                AM_MEDIA_TYPE mt;
1172
                ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
1173
                mt.majortype = MEDIATYPE_Video;
1174
                mt.subtype = MEDIASUBTYPE_RGB24;
1175
                mt.formattype = FORMAT_VideoInfo;
1176
                hr = pGrabber->SetMediaType(&mt);
1177
        }
1178
 
1179
        if (SUCCEEDED(hr))
1180
        {
1181
                hr = pGrabber->SetCallback(new SampleGrabberCB(), 1);
1182
        }
1183
 
1184
        if (pGrabber != NULL)
1185
        {
1186
                pGrabber->Release();
1187
                pGrabber = NULL;
1188
        }
1189
 
1190
        return hr;
1191
}
1192
 
1193
void CameraMethods::GetCaptureSizes(int index, IList<Tuple<int,int,int>^> ^ sizes)
1194
{
1195
        sizes->Clear();
1196
 
1197
        HRESULT hr = S_OK;
1198
 
1199
        if (index >= Count)
1200
                throw gcnew ArgumentException("Camera index is out of bounds: " + Count.ToString());
1201
 
1202
        if (g_aCameraInfo[index].pMoniker == NULL)
1203
                throw gcnew ArgumentException("There is no camera at index: " + index.ToString());
1204
 
1205
        if (g_pGraphBuilder != NULL)
1206
                throw gcnew ArgumentException("Graph Builder was null");
1207
 
1208
        IMoniker *pMoniker = g_aCameraInfo[index].pMoniker;
1209
        pMoniker->AddRef();
1210
 
1211
        IBaseFilter* pCap = NULL;
1212
        // Build the camera from the moniker
1213
        if (SUCCEEDED(hr))
1214
                hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (LPVOID*)&pCap);
1215
 
1216
        ICaptureGraphBuilder2* captureGraphBuilder = NULL;
1217
        if (SUCCEEDED(hr))
1218
        {
1219
                hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
1220
                        NULL,
1221
                        CLSCTX_INPROC,
1222
                        IID_ICaptureGraphBuilder2,
1223
                        (LPVOID*)&captureGraphBuilder);
1224
        }
1225
 
1226
        IAMStreamConfig *pConfig = NULL;
1227
        if(SUCCEEDED(hr))
1228
                hr = captureGraphBuilder->FindInterface(
1229
                &PIN_CATEGORY_CAPTURE,
1230
                &MEDIATYPE_Video,
1231
                pCap, // Pointer to the capture filter.
1232
                IID_IAMStreamConfig, (void**)&pConfig);
1233
 
1234
        int iCount = 0, iSize = 0;
1235
        if(SUCCEEDED(hr))
1236
                hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
1237
 
1238
        // Check the size to make sure we pass in the correct structure.
1239
        if (SUCCEEDED(hr) && iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
1240
        {
1241
                // Use the video capabilities structure.
1242
                for (int iFormat = 0; iFormat < iCount; iFormat++)
1243
                {
1244
                        VIDEO_STREAM_CONFIG_CAPS scc;
1245
                        AM_MEDIA_TYPE *pmt;
1246
                        /* Note:  Use of the VIDEO_STREAM_CONFIG_CAPS structure to configure a video device is
1247
                        deprecated. Although the caller must allocate the buffer, it should ignore the
1248
                        contents after the method returns. The capture device will return its supported
1249
                        formats through the pmt parameter. */
1250
                        hr = pConfig->GetStreamCaps(iFormat, &pmt, (BYTE*)&scc);
1251
                        if (SUCCEEDED(hr))
1252
                        {
1253
                                /* Examine the format, and possibly use it. */
1254
                                if (pmt->formattype == FORMAT_VideoInfo) {
1255
                                        // Check the buffer size.
1256
                                        if (pmt->cbFormat >= sizeof(VIDEOINFOHEADER))
1257
                                        {
1258
                                                VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
1259
                                                BITMAPINFOHEADER *bmiHeader = &pVih->bmiHeader;
1260
 
1261
                                                int width = bmiHeader->biWidth;
1262
                                                int height = bmiHeader->biHeight;
1263
                                                int bitCount = bmiHeader->biBitCount;
1264
 
1265
                                                sizes->Add( gcnew Tuple<int,int,int>( width, height, bitCount ) );
1266
                                        }
1267
                                }
1268
 
1269
                                // Delete the media type when you are done.
1270
                                MyDeleteMediaType(pmt);
1271
                        }
1272
                }
1273
        }
1274
 
1275
        // Cleanup
1276
        if (pMoniker != NULL)
1277
        {
1278
                pMoniker->Release();
1279
                pMoniker = NULL;
1280
        }
1281
}
1282
 
1283
IList<Tuple<int,int,int>^> ^ CameraMethods::CaptureSizes::get()
1284
{
1285
        IList<Tuple<int,int,int>^> ^ result = gcnew List<Tuple<int,int,int>^>();
1286
 
1287
        GetCaptureSizes( ActiveCameraIndex, result );
1288
 
1289
        return result;
1290
}
1291
 
1292
// If bpp is -1, the first format matching the width and height is selected.
1293
// based on http://stackoverflow.com/questions/7383372/cant-make-iamstreamconfig-setformat-to-work-with-lifecam-studio
1294
HRESULT CameraMethods::SetCaptureFormat(IBaseFilter* pCap, int width, int height, int bpp)
1295
{
1296
        HRESULT hr = S_OK;
1297
 
1298
        IAMStreamConfig *pConfig = NULL;
1299
        hr = g_pCaptureGraphBuilder->FindInterface(
1300
                &PIN_CATEGORY_CAPTURE,
1301
                &MEDIATYPE_Video,
1302
                pCap, // Pointer to the capture filter.
1303
                IID_IAMStreamConfig, (void**)&pConfig);
1304
        if (!SUCCEEDED(hr)) return hr;
1305
 
1306
        int iCount = 0, iSize = 0;
1307
        hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);
1308
        if (!SUCCEEDED(hr)) return hr;
1309
 
1310
        // Check the size to make sure we pass in the correct structure.
1311
        if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))
1312
        {
1313
                // Use the video capabilities structure.
1314
                for (int iFormat = 0; iFormat < iCount; iFormat++)
1315
                {
1316
                                VIDEO_STREAM_CONFIG_CAPS scc;
1317
                                AM_MEDIA_TYPE *pmt;
1318
                                /* Note:  Use of the VIDEO_STREAM_CONFIG_CAPS structure to configure a video device is
1319
                                deprecated. Although the caller must allocate the buffer, it should ignore the
1320
                                contents after the method returns. The capture device will return its supported
1321
                                formats through the pmt parameter. */
1322
                                hr = pConfig->GetStreamCaps(iFormat, &pmt, (BYTE*)&scc);
1323
                                if (SUCCEEDED(hr))
1324
                                {
1325
                                        /* Examine the format, and possibly use it. */
1326
                                        if (pmt->formattype == FORMAT_VideoInfo) {
1327
                                                // Check the buffer size.
1328
                                                if (pmt->cbFormat >= sizeof(VIDEOINFOHEADER))
1329
                                                {
1330
                                                                VIDEOINFOHEADER *pVih =  reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
1331
                                                                BITMAPINFOHEADER *bmiHeader = &pVih->bmiHeader;
1332
 
1333
                                                                /* Access VIDEOINFOHEADER members through pVih. */
1334
                                                                if( bmiHeader->biWidth == width && bmiHeader->biHeight == height && ( bmiHeader->biBitCount == -1 || bmiHeader->biBitCount == bpp) )
1335
                                                                {
1336
                                                                        hr = pConfig->SetFormat(pmt);
1337
 
1338
                                                                        break;
1339
                                                                }
1340
                                                }
1341
                                        }
1342
 
1343
                                        // Delete the media type when you are done.
1344
                                        MyDeleteMediaType(pmt);
1345
                                }
1346
                }
1347
        }
1348
 
1349
        return hr;
1350
}