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