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 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 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 101 DeviceInfoDS::~DeviceInfoDS() 102 { 103 RELEASE_AND_CLEAR(_dsMonikerDevEnum); 104 RELEASE_AND_CLEAR(_dsDevEnum); 105 if (_CoUninitializeIsRequired) 106 { 107 CoUninitialize(); 108 } 109 } 110 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 } 123 uint32_t DeviceInfoDS::NumberOfDevices() 124 { 125 ReadLockScoped cs(_apiLock); 126 return GetDeviceInfo(0, 0, 0, 0, 0, 0, 0); 127 } 128 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 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 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 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 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 */ 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 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