device_info_ds.cc revision 10987a851d64803899e9980ba342c389c377db35
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 "device_info_ds.h" 12 13#include "../video_capture_config.h" 14#include "../video_capture_delay.h" 15#include "help_functions_ds.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{ 26const WebRtc_Word32 NoWindowsCaptureDelays = 1; 27const 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 46DeviceInfoDS* DeviceInfoDS::Create(const WebRtc_Word32 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 57DeviceInfoDS::DeviceInfoDS(const WebRtc_Word32 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 101DeviceInfoDS::~DeviceInfoDS() 102{ 103 RELEASE_AND_CLEAR(_dsMonikerDevEnum); 104 RELEASE_AND_CLEAR(_dsDevEnum); 105 if (_CoUninitializeIsRequired) 106 { 107 CoUninitialize(); 108 } 109} 110 111WebRtc_Word32 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} 123WebRtc_UWord32 DeviceInfoDS::NumberOfDevices() 124{ 125 ReadLockScoped cs(_apiLock); 126 return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0); 127} 128 129WebRtc_Word32 DeviceInfoDS::GetDeviceName( 130 WebRtc_UWord32 deviceNumber, 131 char* deviceNameUTF8, 132 WebRtc_UWord32 deviceNameLength, 133 char* deviceUniqueIdUTF8, 134 WebRtc_UWord32 deviceUniqueIdUTF8Length, 135 char* productUniqueIdUTF8, 136 WebRtc_UWord32 productUniqueIdUTF8Length) 137{ 138 ReadLockScoped cs(_apiLock); 139 const WebRtc_Word32 result = GetDeviceInfo(deviceNumber, deviceNameUTF8, 140 deviceNameLength, 141 deviceUniqueIdUTF8, 142 deviceUniqueIdUTF8Length, 143 productUniqueIdUTF8, 144 productUniqueIdUTF8Length); 145 return result > (WebRtc_Word32) deviceNumber ? 0 : -1; 146} 147 148WebRtc_Word32 DeviceInfoDS::GetDeviceInfo( 149 WebRtc_UWord32 deviceNumber, 150 char* deviceNameUTF8, 151 WebRtc_UWord32 deviceNameLength, 152 char* deviceUniqueIdUTF8, 153 WebRtc_UWord32 deviceUniqueIdUTF8Length, 154 char* productUniqueIdUTF8, 155 WebRtc_UWord32 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 275IBaseFilter * DeviceInfoDS::GetDeviceFilter( 276 const char* deviceUniqueIdUTF8, 277 char* productUniqueIdUTF8, 278 WebRtc_UWord32 productUniqueIdUTF8Length) 279{ 280 281 const WebRtc_Word32 deviceUniqueIdUTF8Length = 282 (WebRtc_Word32) 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 369WebRtc_Word32 DeviceInfoDS::GetWindowsCapability( 370 const WebRtc_Word32 capabilityIndex, 371 VideoCaptureCapabilityWindows& windowsCapability) 372 373{ 374 ReadLockScoped cs(_apiLock); 375 // Make sure the number is valid 376 if (capabilityIndex >= _captureCapabilities.Size() || capabilityIndex < 0) 377 return -1; 378 379 MapItem* item = _captureCapabilities.Find(capabilityIndex); 380 if (!item) 381 return -1; 382 383 VideoCaptureCapabilityWindows* capPointer = 384 static_cast<VideoCaptureCapabilityWindows*> (item->GetItem()); 385 windowsCapability = *capPointer; 386 return 0; 387} 388 389WebRtc_Word32 DeviceInfoDS::CreateCapabilityMap( 390 const char* deviceUniqueIdUTF8) 391 392{ 393 // Reset old capability list 394 MapItem* item = NULL; 395 while (item = _captureCapabilities.Last()) 396 { 397 VideoCaptureCapabilityWindows* cap = 398 static_cast<VideoCaptureCapabilityWindows*> (item->GetItem()); 399 delete cap; 400 _captureCapabilities.Erase(item); 401 } 402 403 const WebRtc_Word32 deviceUniqueIdUTF8Length = 404 (WebRtc_Word32) strlen((char*) deviceUniqueIdUTF8); 405 if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength) 406 { 407 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, 408 "Device name too long"); 409 return -1; 410 } 411 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, 412 "CreateCapabilityMap called for device %s", deviceUniqueIdUTF8); 413 414 415 char productId[kVideoCaptureProductIdLength]; 416 IBaseFilter* captureDevice = DeviceInfoDS::GetDeviceFilter( 417 deviceUniqueIdUTF8, 418 productId, 419 kVideoCaptureProductIdLength); 420 if (!captureDevice) 421 return -1; 422 IPin* outputCapturePin = GetOutputPin(captureDevice, GUID_NULL); 423 if (!outputCapturePin) 424 { 425 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, 426 "Failed to get capture device output pin"); 427 RELEASE_AND_CLEAR(captureDevice); 428 return -1; 429 } 430 IAMExtDevice* extDevice = NULL; 431 HRESULT hr = captureDevice->QueryInterface(IID_IAMExtDevice, 432 (void **) &extDevice); 433 if (SUCCEEDED(hr) && extDevice) 434 { 435 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, 436 "This is an external device"); 437 extDevice->Release(); 438 } 439 440 IAMStreamConfig* streamConfig = NULL; 441 hr = outputCapturePin->QueryInterface(IID_IAMStreamConfig, 442 (void**) &streamConfig); 443 if (FAILED(hr)) 444 { 445 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, 446 "Failed to get IID_IAMStreamConfig interface from capture device"); 447 return -1; 448 } 449 450 // this gets the FPS 451 IAMVideoControl* videoControlConfig = NULL; 452 HRESULT hrVC = captureDevice->QueryInterface(IID_IAMVideoControl, 453 (void**) &videoControlConfig); 454 if (FAILED(hrVC)) 455 { 456 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id, 457 "IID_IAMVideoControl Interface NOT SUPPORTED"); 458 } 459 460 AM_MEDIA_TYPE *pmt = NULL; 461 VIDEO_STREAM_CONFIG_CAPS caps; 462 int count, size; 463 464 hr = streamConfig->GetNumberOfCapabilities(&count, &size); 465 if (FAILED(hr)) 466 { 467 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, 468 "Failed to GetNumberOfCapabilities"); 469 RELEASE_AND_CLEAR(videoControlConfig); 470 RELEASE_AND_CLEAR(streamConfig); 471 RELEASE_AND_CLEAR(outputCapturePin); 472 RELEASE_AND_CLEAR(captureDevice); 473 return -1; 474 } 475 476 WebRtc_Word32 index = 0; // Index in created _capabilities map 477 // Check if the device support formattype == FORMAT_VideoInfo2 and FORMAT_VideoInfo. 478 // Prefer FORMAT_VideoInfo since some cameras (ZureCam) has been seen having problem with MJPEG and FORMAT_VideoInfo2 479 // Interlace flag is only supported in FORMAT_VideoInfo2 480 bool supportFORMAT_VideoInfo2 = false; 481 bool supportFORMAT_VideoInfo = false; 482 bool foundInterlacedFormat = false; 483 GUID preferedVideoFormat = FORMAT_VideoInfo; 484 for (WebRtc_Word32 tmp = 0; tmp < count; ++tmp) 485 { 486 hr = streamConfig->GetStreamCaps(tmp, &pmt, 487 reinterpret_cast<BYTE*> (&caps)); 488 if (!FAILED(hr)) 489 { 490 if (pmt->majortype == MEDIATYPE_Video 491 && pmt->formattype == FORMAT_VideoInfo2) 492 { 493 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, 494 " Device support FORMAT_VideoInfo2"); 495 supportFORMAT_VideoInfo2 = true; 496 VIDEOINFOHEADER2* h = 497 reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat); 498 assert(h); 499 foundInterlacedFormat |= h->dwInterlaceFlags 500 & (AMINTERLACE_IsInterlaced 501 | AMINTERLACE_DisplayModeBobOnly); 502 } 503 if (pmt->majortype == MEDIATYPE_Video 504 && pmt->formattype == FORMAT_VideoInfo) 505 { 506 WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, 507 " Device support FORMAT_VideoInfo2"); 508 supportFORMAT_VideoInfo = true; 509 } 510 } 511 } 512 if (supportFORMAT_VideoInfo2) 513 { 514 if (supportFORMAT_VideoInfo && !foundInterlacedFormat) 515 { 516 preferedVideoFormat = FORMAT_VideoInfo; 517 } 518 else 519 { 520 preferedVideoFormat = FORMAT_VideoInfo2; 521 } 522 } 523 524 for (WebRtc_Word32 tmp = 0; tmp < count; ++tmp) 525 { 526 hr = streamConfig->GetStreamCaps(tmp, &pmt, 527 reinterpret_cast<BYTE*> (&caps)); 528 if (FAILED(hr)) 529 { 530 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, 531 "Failed to GetStreamCaps"); 532 RELEASE_AND_CLEAR(videoControlConfig); 533 RELEASE_AND_CLEAR(streamConfig); 534 RELEASE_AND_CLEAR(outputCapturePin); 535 RELEASE_AND_CLEAR(captureDevice); 536 return -1; 537 } 538 539 if (pmt->majortype == MEDIATYPE_Video 540 && pmt->formattype == preferedVideoFormat) 541 { 542 543 VideoCaptureCapabilityWindows* capability = 544 new VideoCaptureCapabilityWindows(); 545 WebRtc_Word64 avgTimePerFrame = 0; 546 547 if (pmt->formattype == FORMAT_VideoInfo) 548 { 549 VIDEOINFOHEADER* h = 550 reinterpret_cast<VIDEOINFOHEADER*> (pmt->pbFormat); 551 assert(h); 552 capability->directShowCapabilityIndex = tmp; 553 capability->width = h->bmiHeader.biWidth; 554 capability->height = h->bmiHeader.biHeight; 555 avgTimePerFrame = h->AvgTimePerFrame; 556 } 557 if (pmt->formattype == FORMAT_VideoInfo2) 558 { 559 VIDEOINFOHEADER2* h = 560 reinterpret_cast<VIDEOINFOHEADER2*> (pmt->pbFormat); 561 assert(h); 562 capability->directShowCapabilityIndex = tmp; 563 capability->width = h->bmiHeader.biWidth; 564 capability->height = h->bmiHeader.biHeight; 565 capability->interlaced = h->dwInterlaceFlags 566 & (AMINTERLACE_IsInterlaced 567 | AMINTERLACE_DisplayModeBobOnly); 568 avgTimePerFrame = h->AvgTimePerFrame; 569 } 570 571 if (hrVC == S_OK) 572 { 573 LONGLONG *frameDurationList; 574 LONGLONG maxFPS; 575 long listSize; 576 SIZE size; 577 size.cx = capability->width; 578 size.cy = capability->height; 579 580 // GetMaxAvailableFrameRate doesn't return max frame rate always 581 // eg: Logitech Notebook. This may be due to a bug in that API 582 // because GetFrameRateList array is reversed in the above camera. So 583 // a util method written. Can't assume the first value will return 584 // the max fps. 585 hrVC = videoControlConfig->GetFrameRateList(outputCapturePin, 586 tmp, size, 587 &listSize, 588 &frameDurationList); 589 590 // On some odd cameras, you may get a 0 for duration. 591 // GetMaxOfFrameArray returns the lowest duration (highest FPS) 592 if (hrVC == S_OK && listSize > 0 && 593 0 != (maxFPS = GetMaxOfFrameArray(frameDurationList, 594 listSize))) 595 { 596 capability->maxFPS = static_cast<int> (10000000 597 / maxFPS); 598 capability->supportFrameRateControl = true; 599 } 600 else // use existing method 601 { 602 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, 603 _id, 604 "GetMaxAvailableFrameRate NOT SUPPORTED"); 605 if (avgTimePerFrame > 0) 606 capability->maxFPS = static_cast<int> (10000000 607 / avgTimePerFrame); 608 else 609 capability->maxFPS = 0; 610 } 611 } 612 else // use existing method in case IAMVideoControl is not supported 613 { 614 if (avgTimePerFrame > 0) 615 capability->maxFPS = static_cast<int> (10000000 616 / avgTimePerFrame); 617 else 618 capability->maxFPS = 0; 619 } 620 621 // can't switch MEDIATYPE :~( 622 if (pmt->subtype == MEDIASUBTYPE_I420) 623 { 624 capability->rawType = kVideoI420; 625 } 626 else if (pmt->subtype == MEDIASUBTYPE_IYUV) 627 { 628 capability->rawType = kVideoIYUV; 629 } 630 else if (pmt->subtype == MEDIASUBTYPE_RGB24) 631 { 632 capability->rawType = kVideoRGB24; 633 } 634 else if (pmt->subtype == MEDIASUBTYPE_YUY2) 635 { 636 capability->rawType = kVideoYUY2; 637 } 638 else if (pmt->subtype == MEDIASUBTYPE_RGB565) 639 { 640 capability->rawType = kVideoRGB565; 641 } 642 else if (pmt->subtype == MEDIASUBTYPE_MJPG) 643 { 644 capability->rawType = kVideoMJPEG; 645 } 646 else if (pmt->subtype == MEDIASUBTYPE_dvsl 647 || pmt->subtype == MEDIASUBTYPE_dvsd 648 || pmt->subtype == MEDIASUBTYPE_dvhd) // If this is an external DV camera 649 { 650 capability->rawType = kVideoYUY2;// MS DV filter seems to create this type 651 } 652 else if (pmt->subtype == MEDIASUBTYPE_UYVY) // Seen used by Declink capture cards 653 { 654 capability->rawType = kVideoUYVY; 655 } 656 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 657 { 658 WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id, 659 "Device support HDYC."); 660 capability->rawType = kVideoUYVY; 661 } 662 else 663 { 664 WCHAR strGuid[39]; 665 StringFromGUID2(pmt->subtype, strGuid, 39); 666 WEBRTC_TRACE( webrtc::kTraceWarning, 667 webrtc::kTraceVideoCapture, _id, 668 "Device support unknown media type %ls, width %d, height %d", 669 strGuid); 670 delete capability; 671 continue; 672 } 673 674 // Get the expected capture delay from the static list 675 capability->expectedCaptureDelay 676 = GetExpectedCaptureDelay(WindowsCaptureDelays, 677 NoWindowsCaptureDelays, 678 productId, 679 capability->width, 680 capability->height); 681 _captureCapabilities.Insert(index++, capability); 682 WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, 683 "Camera capability, width:%d height:%d type:%d fps:%d", 684 capability->width, capability->height, 685 capability->rawType, capability->maxFPS); 686 } 687 DeleteMediaType(pmt); 688 pmt = NULL; 689 } 690 RELEASE_AND_CLEAR(streamConfig); 691 RELEASE_AND_CLEAR(videoControlConfig); 692 RELEASE_AND_CLEAR(outputCapturePin); 693 RELEASE_AND_CLEAR(captureDevice); // Release the capture device 694 695 // Store the new used device name 696 _lastUsedDeviceNameLength = deviceUniqueIdUTF8Length; 697 _lastUsedDeviceName = (char*) realloc(_lastUsedDeviceName, 698 _lastUsedDeviceNameLength 699 + 1); 700 memcpy(_lastUsedDeviceName, deviceUniqueIdUTF8, _lastUsedDeviceNameLength+ 1); 701 WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, _id, 702 "CreateCapabilityMap %d", _captureCapabilities.Size()); 703 704 return _captureCapabilities.Size(); 705} 706 707/* Constructs a product ID from the Windows DevicePath. on a USB device the devicePath contains product id and vendor id. 708 This seems to work for firewire as well 709 /* Example of device path 710 "\\?\usb#vid_0408&pid_2010&mi_00#7&258e7aaf&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" 711 "\\?\avc#sony&dv-vcr&camcorder&dv#65b2d50301460008#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\global" 712 */ 713void DeviceInfoDS::GetProductId(const char* devicePath, 714 char* productUniqueIdUTF8, 715 WebRtc_UWord32 productUniqueIdUTF8Length) 716{ 717 *productUniqueIdUTF8 = '\0'; 718 char* startPos = strstr((char*) devicePath, "\\\\?\\"); 719 if (!startPos) 720 { 721 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1); 722 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, 723 "Failed to get the product Id"); 724 return; 725 } 726 startPos += 4; 727 728 char* pos = strchr(startPos, '&'); 729 if (!pos || pos >= (char*) devicePath + strlen((char*) devicePath)) 730 { 731 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1); 732 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, 733 "Failed to get the product Id"); 734 return; 735 } 736 // Find the second occurrence. 737 pos = strchr(pos + 1, '&'); 738 WebRtc_UWord32 bytesToCopy = (WebRtc_UWord32)(pos - startPos); 739 if (pos && (bytesToCopy <= productUniqueIdUTF8Length) && bytesToCopy 740 <= kVideoCaptureProductIdLength) 741 { 742 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, 743 (char*) startPos, bytesToCopy); 744 } 745 else 746 { 747 strncpy_s((char*) productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1); 748 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, 749 "Failed to get the product Id"); 750 } 751} 752 753WebRtc_Word32 DeviceInfoDS::DisplayCaptureSettingsDialogBox( 754 const char* deviceUniqueIdUTF8, 755 const char* dialogTitleUTF8, 756 void* parentWindow, 757 WebRtc_UWord32 positionX, 758 WebRtc_UWord32 positionY) 759{ 760 ReadLockScoped cs(_apiLock); 761 HWND window = (HWND) parentWindow; 762 763 IBaseFilter* filter = GetDeviceFilter(deviceUniqueIdUTF8, NULL, 0); 764 if (!filter) 765 return -1; 766 767 ISpecifyPropertyPages* pPages = NULL; 768 CAUUID uuid; 769 HRESULT hr = S_OK; 770 771 hr = filter->QueryInterface(IID_ISpecifyPropertyPages, (LPVOID*) &pPages); 772 if (!SUCCEEDED(hr)) 773 { 774 filter->Release(); 775 return -1; 776 } 777 hr = pPages->GetPages(&uuid); 778 if (!SUCCEEDED(hr)) 779 { 780 filter->Release(); 781 return -1; 782 } 783 784 WCHAR tempDialogTitleWide[256]; 785 tempDialogTitleWide[0] = 0; 786 int size = 255; 787 788 // UTF-8 to wide char 789 MultiByteToWideChar(CP_UTF8, 0, (char*) dialogTitleUTF8, -1, 790 tempDialogTitleWide, size); 791 792 // Invoke a dialog box to display. 793 794 hr = OleCreatePropertyFrame(window, // You must create the parent window. 795 positionX, // Horizontal position for the dialog box. 796 positionY, // Vertical position for the dialog box. 797 tempDialogTitleWide,// String used for the dialog box caption. 798 1, // Number of pointers passed in pPlugin. 799 (LPUNKNOWN*) &filter, // Pointer to the filter. 800 uuid.cElems, // Number of property pages. 801 uuid.pElems, // Array of property page CLSIDs. 802 LOCALE_USER_DEFAULT, // Locale ID for the dialog box. 803 0, NULL); // Reserved 804 // Release memory. 805 if (uuid.pElems) 806 { 807 CoTaskMemFree(uuid.pElems); 808 } 809 filter->Release(); 810 return 0; 811} 812} // namespace videocapturemodule 813} // namespace webrtc 814