blob: 5f3171ec8cca2676c2327004c6e0d9d3df8a3523 [file] [log] [blame]
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "device_info_windows.h"
12
13#include "../video_capture_config.h"
14#include "help_functions_windows.h"
15#include "capture_delay_values_windows.h"
16#include "ref_count.h"
17#include "trace.h"
18
19#include <Streams.h>
20#include <Dvdmedia.h>
21
22namespace webrtc
23{
24namespace videocapturemodule
25{
26VideoCaptureModule::DeviceInfo* VideoCaptureImpl::CreateDeviceInfo(
27 const WebRtc_Word32 id)
28{
29 videocapturemodule::DeviceInfoWindows* dsInfo =
30 new videocapturemodule::DeviceInfoWindows(id);
31
32 if (!dsInfo || dsInfo->Init() != 0)
33 {
34 delete dsInfo;
35 dsInfo = NULL;
36 }
37 return dsInfo;
38}
39
40DeviceInfoWindows::DeviceInfoWindows(const WebRtc_Word32 id)
41 : DeviceInfoImpl(id), _dsDevEnum(NULL), _dsMonikerDevEnum(NULL),
42 _CoUninitializeIsRequired(true)
43{
44 // 1) Initialize the COM library (make Windows load the DLLs).
45 //
46 // CoInitializeEx must be called at least once, and is usually called only once,
47 // for each thread that uses the COM library. Multiple calls to CoInitializeEx
48 // by the same thread are allowed as long as they pass the same concurrency flag,
49 // but subsequent valid calls return S_FALSE.
50 // To close the COM library gracefully on a thread, each successful call to
51 // CoInitializeEx, including any call that returns S_FALSE, must be balanced
52 // by a corresponding call to CoUninitialize.
53 //
54
55 /*Apartment-threading, while allowing for multiple threads of execution,
56 serializes all incoming calls by requiring that calls to methods of objects created by this thread always run on the same thread
57 the apartment/thread that created them. In addition, calls can arrive only at message-queue boundaries (i.e., only during a
58 PeekMessage, SendMessage, DispatchMessage, etc.). Because of this serialization, it is not typically necessary to write concurrency control into
59 the code for the object, other than to avoid calls to PeekMessage and SendMessage during processing that must not be interrupted by other method
60 invocations or calls to other objects in the same apartment/thread.*/
61
62 ///CoInitializeEx(NULL, COINIT_APARTMENTTHREADED ); //| COINIT_SPEED_OVER_MEMORY
63 HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); // Use COINIT_MULTITHREADED since Voice Engine uses COINIT_MULTITHREADED
64 if (FAILED(hr))
65 {
66 // Avoid calling CoUninitialize() since CoInitializeEx() failed.
67 _CoUninitializeIsRequired = FALSE;
68
69 if (hr == RPC_E_CHANGED_MODE)
70 {
71 // Calling thread has already initialized COM to be used in a single-threaded
72 // apartment (STA). We are then prevented from using STA.
73 // Details: hr = 0x80010106 <=> "Cannot change thread mode after it is set".
74 //
75 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
76 "VideoCaptureWindowsDSInfo::VideoCaptureWindowsDSInfo "
77 "CoInitializeEx(NULL, COINIT_APARTMENTTHREADED) => "
78 "RPC_E_CHANGED_MODE, error 0x%x",
79 hr);
80 }
81 }
82}
83
84DeviceInfoWindows::~DeviceInfoWindows()
85{
86 RELEASE_AND_CLEAR(_dsMonikerDevEnum);
87 RELEASE_AND_CLEAR(_dsDevEnum);
88 if (_CoUninitializeIsRequired)
89 {
90 CoUninitialize();
91 }
92}
93
94WebRtc_Word32 DeviceInfoWindows::Init()
95{
96 HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
97 IID_ICreateDevEnum, (void **) &_dsDevEnum);
98 if (hr != NOERROR)
99 {
100 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
101 "Failed to create CLSID_SystemDeviceEnum, error 0x%x", hr);
102 return -1;
103 }
104 return 0;
105}
106WebRtc_UWord32 DeviceInfoWindows::NumberOfDevices()
107{
108 ReadLockScoped cs(_apiLock);
109 return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0);
110
111}
112WebRtc_Word32 DeviceInfoWindows::GetDeviceName(
113 WebRtc_UWord32 deviceNumber,
114 char* deviceNameUTF8,
115 WebRtc_UWord32 deviceNameLength,
116 char* deviceUniqueIdUTF8,
117 WebRtc_UWord32 deviceUniqueIdUTF8Length,
118 char* productUniqueIdUTF8,
119 WebRtc_UWord32 productUniqueIdUTF8Length)
120{
121 ReadLockScoped cs(_apiLock);
122 const WebRtc_Word32 result = GetDeviceInfo(deviceNumber, deviceNameUTF8,
123 deviceNameLength,
124 deviceUniqueIdUTF8,
125 deviceUniqueIdUTF8Length,
126 productUniqueIdUTF8,
127 productUniqueIdUTF8Length);
128 return result > (WebRtc_Word32) deviceNumber ? 0 : -1;
129}
130
131WebRtc_Word32 DeviceInfoWindows::GetDeviceInfo(
132 WebRtc_UWord32 deviceNumber,
133 char* deviceNameUTF8,
134 WebRtc_UWord32 deviceNameLength,
135 char* deviceUniqueIdUTF8,
136 WebRtc_UWord32 deviceUniqueIdUTF8Length,
137 char* productUniqueIdUTF8,
138 WebRtc_UWord32 productUniqueIdUTF8Length)
139
140{
141
142 // enumerate all video capture devices
143 RELEASE_AND_CLEAR(_dsMonikerDevEnum);
144 HRESULT hr =
145 _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
146 &_dsMonikerDevEnum, 0);
147 if (hr != NOERROR)
148 {
149 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
150 "Failed to enumerate CLSID_SystemDeviceEnum, error 0x%x."
151 " No webcam exist?", hr);
152 return 0;
153 }
154
155 _dsMonikerDevEnum->Reset();
156 ULONG cFetched;
157 IMoniker *pM;
158 int index = 0;
159 while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched))
160 {
161 IPropertyBag *pBag;
162 hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **) &pBag);
163 if (S_OK == hr)
164 {
165 // Find the description or friendly name.
166 VARIANT varName;
167 VariantInit(&varName);
168 hr = pBag->Read(L"Description", &varName, 0);
169 if (FAILED(hr))
170 {
171 hr = pBag->Read(L"FriendlyName", &varName, 0);
172 }
173 if (SUCCEEDED(hr))
174 {
175 // ignore all VFW drivers
176 if ((wcsstr(varName.bstrVal, (L"(VFW)")) == NULL) &&
177 (_wcsnicmp(varName.bstrVal, (L"Google Camera Adapter"),21)
178 != 0))
179 {
180 // Found a valid device
181 if (index == deviceNumber) // This is the device we are interested in.
182 {
183 int convResult = 0;
184 if (deviceNameLength > 0)
185 {
186 convResult = WideCharToMultiByte(CP_UTF8, 0,
187 varName.bstrVal, -1,
188 (char*) deviceNameUTF8,
189 deviceNameLength, NULL,
190 NULL);
191 if (convResult == 0)
192 {
193 WEBRTC_TRACE(webrtc::kTraceError,
194 webrtc::kTraceVideoCapture, _id,
195 "Failed to convert device name to UTF8. %d",
196 GetLastError());
197 return -1;
198 }
199 }
200 if (deviceUniqueIdUTF8Length > 0)
201 {
202 hr = pBag->Read(L"DevicePath", &varName, 0);
203 if (FAILED(hr))
204 {
205 strncpy_s((char *) deviceUniqueIdUTF8,
206 deviceUniqueIdUTF8Length,
207 (char *) deviceNameUTF8, convResult);
208 WEBRTC_TRACE(webrtc::kTraceError,
209 webrtc::kTraceVideoCapture, _id,
210 "Failed to get deviceUniqueIdUTF8 using deviceNameUTF8");
211 }
212 else
213 {
214 convResult = WideCharToMultiByte(
215 CP_UTF8,
216 0,
217 varName.bstrVal,
218 -1,
219 (char*) deviceUniqueIdUTF8,
220 deviceUniqueIdUTF8Length,
221 NULL, NULL);
222 if (convResult == 0)
223 {
224 WEBRTC_TRACE(webrtc::kTraceError,
225 webrtc::kTraceVideoCapture, _id,
226 "Failed to convert device name to UTF8. %d",
227 GetLastError());
228 return -1;
229 }
230 if (productUniqueIdUTF8
231 && productUniqueIdUTF8Length > 0)
232 {
233 GetProductId(deviceUniqueIdUTF8,
234 productUniqueIdUTF8,
235 productUniqueIdUTF8Length);
236 }
237 }
238 }
239
240 }
241 ++index; // increase the number of valid devices
242 }
243 }
244 VariantClear(&varName);
245 pBag->Release();
246 pM->Release();
247 }
248
249 }
250 if (deviceNameLength)
251 {
252 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, "%s %s",
253 __FUNCTION__, deviceNameUTF8);
254 }
255 return index;
256}
257
258IBaseFilter * DeviceInfoWindows::GetDeviceFilter(
259 const char* deviceUniqueIdUTF8,
260 char* productUniqueIdUTF8,
261 WebRtc_UWord32 productUniqueIdUTF8Length)
262{
263
264 const WebRtc_Word32 deviceUniqueIdUTF8Length =
265 (WebRtc_Word32) strlen((char*) deviceUniqueIdUTF8); // UTF8 is also NULL terminated
266 if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
267 {
268 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
269 "Device name too long");
270 return NULL;
271 }
272
273 // enumerate all video capture devices
274 RELEASE_AND_CLEAR(_dsMonikerDevEnum);
275 HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
276 &_dsMonikerDevEnum, 0);
277 if (hr != NOERROR)
278 {
279 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
280 "Failed to enumerate CLSID_SystemDeviceEnum, error 0x%x."
281 " No webcam exist?", hr);
282 return 0;
283 }
284 _dsMonikerDevEnum->Reset();
285 ULONG cFetched;
286 IMoniker *pM;
287
288 IBaseFilter *captureFilter = NULL;
289 bool deviceFound = false;
290 while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound)
291 {
292 IPropertyBag *pBag;
293 hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void **) &pBag);
294 if (S_OK == hr)
295 {
296 // Find the description or friendly name.
297 VARIANT varName;
298 VariantInit(&varName);
299 if (deviceUniqueIdUTF8Length > 0)
300 {
301 hr = pBag->Read(L"DevicePath", &varName, 0);
302 if (FAILED(hr))
303 {
304 hr = pBag->Read(L"Description", &varName, 0);
305 if (FAILED(hr))
306 {
307 hr = pBag->Read(L"FriendlyName", &varName, 0);
308 }
309 }
310 if (SUCCEEDED(hr))
311 {
312 char tempDevicePathUTF8[256];
313 tempDevicePathUTF8[0] = 0;
314 WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,
315 tempDevicePathUTF8,
316 sizeof(tempDevicePathUTF8), NULL,
317 NULL);
318 if (strncmp(tempDevicePathUTF8,
319 (const char*) deviceUniqueIdUTF8,
320 deviceUniqueIdUTF8Length) == 0)
321 {
322 // We have found the requested device
323 deviceFound = true;
324 hr = pM->BindToObject(0, 0, IID_IBaseFilter,
325 (void**) &captureFilter);
326 if FAILED(hr)
327 {
328 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture,
329 _id, "Failed to bind to the selected capture device %d",hr);
330 }
331
332 if (productUniqueIdUTF8
333 && productUniqueIdUTF8Length > 0) // Get the device name
334 {
335
336 GetProductId(deviceUniqueIdUTF8,
337 productUniqueIdUTF8,
338 productUniqueIdUTF8Length);
339 }
340
341 }
342 }
343 }
344 VariantClear(&varName);
345 pBag->Release();
346 pM->Release();
347 }
348 }
349 return captureFilter;
350}
351
352WebRtc_Word32 DeviceInfoWindows::GetWindowsCapability(
353 const WebRtc_Word32 capabilityIndex,
354 VideoCaptureCapabilityWindows& windowsCapability)
355
356{
357 ReadLockScoped cs(_apiLock);
358 // Make sure the number is valid
359 if (capabilityIndex >= _captureCapabilities.Size() || capabilityIndex < 0)
360 return -1;
361
362 MapItem* item = _captureCapabilities.Find(capabilityIndex);
363 if (!item)
364 return -1;
365
366 VideoCaptureCapabilityWindows* capPointer =
367 static_cast<VideoCaptureCapabilityWindows*> (item->GetItem());
368 windowsCapability = *capPointer;
369 return 0;
370}
371
372WebRtc_Word32 DeviceInfoWindows::CreateCapabilityMap(
373 const char* deviceUniqueIdUTF8)
374
375{
376 // Reset old capability list
377 MapItem* item = NULL;
378 while (item = _captureCapabilities.Last())
379 {
380 VideoCaptureCapabilityWindows* cap =
381 static_cast<VideoCaptureCapabilityWindows*> (item->GetItem());
382 delete cap;
383 _captureCapabilities.Erase(item);
384 }
385
386 const WebRtc_Word32 deviceUniqueIdUTF8Length =
387 (WebRtc_Word32) strlen((char*) deviceUniqueIdUTF8);
388 if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength)
389 {
390 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
391 "Device name too long");
392 return -1;
393 }
394 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
395 "CreateCapabilityMap called for device %s", deviceUniqueIdUTF8);
396
397
398 char productId[kVideoCaptureProductIdLength];
399 IBaseFilter* captureDevice = DeviceInfoWindows::GetDeviceFilter(
400 deviceUniqueIdUTF8,
401 productId,
402 kVideoCaptureProductIdLength);
403 if (!captureDevice)
404 return -1;
405 IPin* outputCapturePin = GetOutputPin(captureDevice);
406 if (!outputCapturePin)
407 {
408 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
409 "Failed to get capture device output pin");
410 RELEASE_AND_CLEAR(captureDevice);
411 return -1;
412 }
413 IAMExtDevice* extDevice = NULL;
414 HRESULT hr = captureDevice->QueryInterface(IID_IAMExtDevice,
415 (void **) &extDevice);
416 if (SUCCEEDED(hr) && extDevice)
417 {
418 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
419 "This is an external device");
420 extDevice->Release();
421 }
422
423 IAMStreamConfig* streamConfig = NULL;
424 hr = outputCapturePin->QueryInterface(IID_IAMStreamConfig,
425 (void**) &streamConfig);
426 if (FAILED(hr))
427 {
428 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
429 "Failed to get IID_IAMStreamConfig interface from capture device");
430 return -1;
431 }
432
433 // this gets the FPS
434 IAMVideoControl* videoControlConfig = NULL;
435 HRESULT hrVC = captureDevice->QueryInterface(IID_IAMVideoControl,
436 (void**) &videoControlConfig);
437 if (FAILED(hrVC))
438 {
439 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
440 "IID_IAMVideoControl Interface NOT SUPPORTED");
441 }
442
443 AM_MEDIA_TYPE *pmt = NULL;
444 VIDEO_STREAM_CONFIG_CAPS caps;
445 int count, size;
446
447 hr = streamConfig->GetNumberOfCapabilities(&count, &size);
448 if (FAILED(hr))
449 {
450 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
451 "Failed to GetNumberOfCapabilities");
452 RELEASE_AND_CLEAR(videoControlConfig);
453 RELEASE_AND_CLEAR(streamConfig);
454 RELEASE_AND_CLEAR(outputCapturePin);
455 RELEASE_AND_CLEAR(captureDevice);
456 return -1;
457 }
458
459 WebRtc_Word32 index = 0; // Index in created _capabilities map
460 // Check if the device support formattype == FORMAT_VideoInfo2 and FORMAT_VideoInfo.
461 // Prefer FORMAT_VideoInfo since some cameras (ZureCam) has been seen having problem with MJPEG and FORMAT_VideoInfo2
462 // Interlace flag is only supported in FORMAT_VideoInfo2
463 bool supportFORMAT_VideoInfo2 = false;
464 bool supportFORMAT_VideoInfo = false;
465 bool foundInterlacedFormat = false;
466 GUID preferedVideoFormat = FORMAT_VideoInfo;
467 for (WebRtc_Word32 tmp = 0; tmp < count; ++tmp)
468 {
469 hr = streamConfig->GetStreamCaps(tmp, &pmt,
470 reinterpret_cast<BYTE*> (&caps));
471 if (!FAILED(hr))
472 {
473 if (pmt->majortype == MEDIATYPE_Video
474 && pmt->formattype == FORMAT_VideoInfo2)
475 {
476 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id,
477 " Device support FORMAT_VideoInfo2");
478 supportFORMAT_VideoInfo2 = true;
479 VIDEOINFOHEADER2* h =
480 reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat);
481 assert(h);
482 foundInterlacedFormat |= h->dwInterlaceFlags
483 & (AMINTERLACE_IsInterlaced
484 | AMINTERLACE_DisplayModeBobOnly);
485 }
486 if (pmt->majortype == MEDIATYPE_Video
487 && pmt->formattype == FORMAT_VideoInfo)
488 {
489 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id,
490 " Device support FORMAT_VideoInfo2");
491 supportFORMAT_VideoInfo = true;
492 }
493 }
494 }
495 if (supportFORMAT_VideoInfo2)
496 {
497 if (supportFORMAT_VideoInfo && !foundInterlacedFormat)
498 {
499 preferedVideoFormat = FORMAT_VideoInfo;
500 }
501 else
502 {
503 preferedVideoFormat = FORMAT_VideoInfo2;
504 }
505 }
506
507 for (WebRtc_Word32 tmp = 0; tmp < count; ++tmp)
508 {
509 hr = streamConfig->GetStreamCaps(tmp, &pmt,
510 reinterpret_cast<BYTE*> (&caps));
511 if (FAILED(hr))
512 {
513 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id,
514 "Failed to GetStreamCaps");
515 RELEASE_AND_CLEAR(videoControlConfig);
516 RELEASE_AND_CLEAR(streamConfig);
517 RELEASE_AND_CLEAR(outputCapturePin);
518 RELEASE_AND_CLEAR(captureDevice);
519 return -1;
520 }
521
522 if (pmt->majortype == MEDIATYPE_Video
523 && pmt->formattype == preferedVideoFormat)
524 {
525
526 VideoCaptureCapabilityWindows* capability =
527 new VideoCaptureCapabilityWindows();
528 WebRtc_Word64 avgTimePerFrame = 0;
529
530 if (pmt->formattype == FORMAT_VideoInfo)
531 {
532 VIDEOINFOHEADER* h =
533 reinterpret_cast<VIDEOINFOHEADER*> (pmt->pbFormat);
534 assert(h);
535 capability->directShowCapabilityIndex = tmp;
536 capability->width = h->bmiHeader.biWidth;
537 capability->height = h->bmiHeader.biHeight;
538 avgTimePerFrame = h->AvgTimePerFrame;
539 }
540 if (pmt->formattype == FORMAT_VideoInfo2)
541 {
542 VIDEOINFOHEADER2* h =
543 reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat);
544 assert(h);
545 capability->directShowCapabilityIndex = tmp;
546 capability->width = h->bmiHeader.biWidth;
547 capability->height = h->bmiHeader.biHeight;
548 capability->interlaced = h->dwInterlaceFlags
549 & (AMINTERLACE_IsInterlaced
550 | AMINTERLACE_DisplayModeBobOnly);
551 avgTimePerFrame = h->AvgTimePerFrame;
552 }
553
554 if (hrVC == S_OK)
555 {
556 LONGLONG *maxFps; // array
557 long listSize;
558 SIZE size;
559 size.cx = capability->width;
560 size.cy = capability->height;
561
562 // GetMaxAvailableFrameRate doesn't return max frame rate always
563 // eg: Logitech Notebook. This may be due to a bug in that API
564 // because GetFrameRateList array is reversed in the above camera. So
565 // a util method written. Can't assume the first value will return
566 // the max fps.
567 hrVC = videoControlConfig->GetFrameRateList(outputCapturePin,
568 tmp, size,
569 &listSize,
570 &maxFps);
571
572 if (hrVC == S_OK && listSize > 0)
573 {
574 LONGLONG maxFPS = GetMaxOfFrameArray(maxFps, listSize);
575 capability->maxFPS = static_cast<int> (10000000
576 / maxFPS);
577 capability->supportFrameRateControl = true;
578 }
579 else // use existing method
580 {
581 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture,
582 _id,
583 "GetMaxAvailableFrameRate NOT SUPPORTED");
584 if (avgTimePerFrame > 0)
585 capability->maxFPS = static_cast<int> (10000000
586 / avgTimePerFrame);
587 else
588 capability->maxFPS = 0;
589 }
590 }
591 else // use existing method in case IAMVideoControl is not supported
592 {
593 if (avgTimePerFrame > 0)
594 capability->maxFPS = static_cast<int> (10000000
595 / avgTimePerFrame);
596 else
597 capability->maxFPS = 0;
598 }
599
600 // can't switch MEDIATYPE :~(
601 if (pmt->subtype == MEDIASUBTYPE_I420)
602 {
603 capability->rawType = kVideoI420;
604 }
605 else if (pmt->subtype == MEDIASUBTYPE_IYUV)
606 {
607 capability->rawType = kVideoIYUV;
608 }
609 else if (pmt->subtype == MEDIASUBTYPE_RGB24)
610 {
611 capability->rawType = kVideoRGB24;
612 }
613 else if (pmt->subtype == MEDIASUBTYPE_YUY2)
614 {
615 capability->rawType = kVideoYUY2;
616 }
617 else if (pmt->subtype == MEDIASUBTYPE_RGB565)
618 {
619 capability->rawType = kVideoRGB565;
620 }
621 else if (pmt->subtype == MEDIASUBTYPE_MJPG)
622 {
623 capability->rawType = kVideoMJPEG;
624 }
625 else if (pmt->subtype == MEDIASUBTYPE_dvsl
626 || pmt->subtype == MEDIASUBTYPE_dvsd
627 || pmt->subtype == MEDIASUBTYPE_dvhd) // If this is an external DV camera
628 {
629 capability->rawType = kVideoYUY2;// MS DV filter seems to create this type
630 }
631 else if (pmt->subtype == MEDIASUBTYPE_UYVY) // Seen used by Declink capture cards
632 {
633 capability->rawType = kVideoUYVY;
634 }
635 else if (pmt->subtype == MEDIASUBTYPE_HDYC) // Seen used by Declink capture cards. Uses BT. 709 color. Not entiry correct to use UYVY. http://en.wikipedia.org/wiki/YCbCr
636 {
637 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id,
638 "Device support HDYC.");
639 capability->rawType = kVideoUYVY;
640 }
641 else
642 {
643 WCHAR strGuid[39];
644 StringFromGUID2(pmt->subtype, strGuid, 39);
645 WEBRTC_TRACE( webrtc::kTraceWarning,
646 webrtc::kTraceVideoCapture, _id,
647 "Device support unknown media type %ls, width %d, height %d",
648 strGuid);
649 delete capability;
650 continue;
651 }
652
653 // Get the expected capture delay from the static list
654 capability->expectedCaptureDelay
655 = GetExpectedCaptureDelay(WindowsCaptureDelays,
656 NoWindowsCaptureDelays,
657 productId,
658 capability->width,
659 capability->height);
660 _captureCapabilities.Insert(index++, capability);
661 WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
662 "Camera capability, width:%d height:%d type:%d fps:%d",
663 capability->width, capability->height,
664 capability->rawType, capability->maxFPS);
665 }
666 DeleteMediaType(pmt);
667 pmt = NULL;
668 }
669 RELEASE_AND_CLEAR(streamConfig);
670 RELEASE_AND_CLEAR(videoControlConfig);
671 RELEASE_AND_CLEAR(outputCapturePin);
672 RELEASE_AND_CLEAR(captureDevice); // Release the capture device
673
674 // Store the new used device name
675 _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length;
676 _lastUsedDeviceName = (char*) realloc(_lastUsedDeviceName,
677 _lastUsedDeviceNameLength
678 + 1);
679 memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8, _lastUsedDeviceNameLength+ 1);
680 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id,
681 "CreateCapabilityMap %d", _captureCapabilities.Size());
682
683 return _captureCapabilities.Size();
684}
685
686/* Constructs a product ID from the Windows DevicePath. on a USB device the devicePath contains product id and vendor id.
687 This seems to work for firewire as well
688 /* Example of device path
689 "\\?\usb#vid_0408&pid_2010&mi_00#7&258e7aaf&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
690 "\\?\avc#sony&dv-vcr&camcorder&dv#65b2d50301460008#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global"
691 */
692void DeviceInfoWindows::GetProductId(const char* devicePath,
693 char* productUniqueIdUTF8,
694 WebRtc_UWord32 productUniqueIdUTF8Length)
695{
696 *productUniqueIdUTF8 = '\0';
697 char* startPos = strstr((char*) devicePath, "\\\\?\\");
698 if (!startPos)
699 {
700 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
701 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
702 "Failed to get the product Id");
703 return;
704 }
705 startPos += 4;
706
707 char* pos = strchr(startPos, '&');
708 if (!pos || pos >= (char*) devicePath + strlen((char*) devicePath))
709 {
710 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
711 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
712 "Failed to get the product Id");
713 return;
714 }
715 // Find the second occurence
716 pos = strchr(pos + 1, '&');
717 WebRtc_UWord32 bytesToCopy = (WebRtc_UWord32)(pos - startPos);
718 if (pos && (bytesToCopy <= productUniqueIdUTF8Length) && bytesToCopy
719 <= kVideoCaptureProductIdLength)
720 {
721 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length,
722 (char*) startPos, bytesToCopy);
723 }
724 else
725 {
726 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
727 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1,
728 "Failed to get the product Id");
729 }
730}
731
732WebRtc_Word32 DeviceInfoWindows::DisplayCaptureSettingsDialogBox(
733 const char* deviceUniqueIdUTF8,
734 const char* dialogTitleUTF8,
735 void* parentWindow,
736 WebRtc_UWord32 positionX,
737 WebRtc_UWord32 positionY)
738{
739 ReadLockScoped cs(_apiLock);
740 HWND window = (HWND) parentWindow;
741
742 IBaseFilter* filter = GetDeviceFilter(deviceUniqueIdUTF8, NULL, 0);
743 if (!filter)
744 return -1;
745
746 ISpecifyPropertyPages* pPages = NULL;
747 CAUUID uuid;
748 HRESULT hr = S_OK;
749
750 hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (LPVOID*) &pPages);
751 if (!SUCCEEDED(hr))
752 {
753 filter->Release();
754 return -1;
755 }
756 hr = pPages->GetPages(&uuid);
757 if (!SUCCEEDED(hr))
758 {
759 filter->Release();
760 return -1;
761 }
762
763 WCHAR tempDialogTitleWide[256];
764 tempDialogTitleWide[0] = 0;
765 int size = 255;
766
767 // UTF-8 to wide char
768 MultiByteToWideChar(CP_UTF8, 0, (char*) dialogTitleUTF8, -1,
769 tempDialogTitleWide, size);
770
771 // Invoke a dialog box to display.
772
773 hr = OleCreatePropertyFrame(window, // You must create the parent window.
774 positionX, // Horizontal position for the dialog box.
775 positionY, // Vertical position for the dialog box.
776 tempDialogTitleWide,// String used for the dialog box caption.
777 1, // Number of pointers passed in pPlugin.
778 (LPUNKNOWN*) &filter, // Pointer to the filter.
779 uuid.cElems, // Number of property pages.
780 uuid.pElems, // Array of property page CLSIDs.
781 LOCALE_USER_DEFAULT, // Locale ID for the dialog box.
782 0, NULL); // Reserved
783 // Release memory.
784 if (uuid.pElems)
785 {
786 CoTaskMemFree(uuid.pElems);
787 }
788 filter->Release();
789 return 0;
790}
791} // namespace videocapturemodule
792} // namespace webrtc