Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2485 | - | 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 | } |