| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/capture/video/win/video_capture_device_factory_win.h" | |
| 6 | |
| 7 #include <mfapi.h> | |
| 8 #include <mferror.h> | |
| 9 #include <stddef.h> | |
| 10 | |
| 11 #include "base/command_line.h" | |
| 12 #include "base/macros.h" | |
| 13 #include "base/metrics/histogram.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/sys_string_conversions.h" | |
| 16 #include "base/win/scoped_co_mem.h" | |
| 17 #include "base/win/scoped_variant.h" | |
| 18 #include "base/win/windows_version.h" | |
| 19 #include "media/base/media_switches.h" | |
| 20 #include "media/base/win/mf_initializer.h" | |
| 21 #include "media/capture/video/win/video_capture_device_mf_win.h" | |
| 22 #include "media/capture/video/win/video_capture_device_win.h" | |
| 23 | |
| 24 using base::win::ScopedCoMem; | |
| 25 using base::win::ScopedComPtr; | |
| 26 using base::win::ScopedVariant; | |
| 27 using Descriptor = media::VideoCaptureDeviceDescriptor; | |
| 28 using Descriptors = media::VideoCaptureDeviceDescriptors; | |
| 29 | |
| 30 namespace media { | |
| 31 | |
| 32 // In Windows device identifiers, the USB VID and PID are preceded by the string | |
| 33 // "vid_" or "pid_". The identifiers are each 4 bytes long. | |
| 34 const char kVidPrefix[] = "vid_"; // Also contains '\0'. | |
| 35 const char kPidPrefix[] = "pid_"; // Also contains '\0'. | |
| 36 const size_t kVidPidSize = 4; | |
| 37 | |
| 38 // Avoid enumerating and/or using certain devices due to they provoking crashes | |
| 39 // or any other reason (http://crbug.com/378494). This enum is defined for the | |
| 40 // purposes of UMA collection. Existing entries cannot be removed. | |
| 41 enum BlacklistedCameraNames { | |
| 42 BLACKLISTED_CAMERA_GOOGLE_CAMERA_ADAPTER = 0, | |
| 43 BLACKLISTED_CAMERA_IP_CAMERA = 1, | |
| 44 BLACKLISTED_CAMERA_CYBERLINK_WEBCAM_SPLITTER = 2, | |
| 45 BLACKLISTED_CAMERA_EPOCCAM = 3, | |
| 46 // This one must be last, and equal to the previous enumerated value. | |
| 47 BLACKLISTED_CAMERA_MAX = BLACKLISTED_CAMERA_EPOCCAM, | |
| 48 }; | |
| 49 | |
| 50 // Blacklisted devices are identified by a characteristic prefix of the name. | |
| 51 // This prefix is used case-insensitively. This list must be kept in sync with | |
| 52 // |BlacklistedCameraNames|. | |
| 53 static const char* const kBlacklistedCameraNames[] = { | |
| 54 // Name of a fake DirectShow filter on computers with GTalk installed. | |
| 55 "Google Camera Adapter", | |
| 56 // The following software WebCams cause crashes. | |
| 57 "IP Camera [JPEG/MJPEG]", "CyberLink Webcam Splitter", "EpocCam", | |
| 58 }; | |
| 59 static_assert(arraysize(kBlacklistedCameraNames) == BLACKLISTED_CAMERA_MAX + 1, | |
| 60 "kBlacklistedCameraNames should be same size as " | |
| 61 "BlacklistedCameraNames enum"); | |
| 62 | |
| 63 static bool LoadMediaFoundationDlls() { | |
| 64 static const wchar_t* const kMfDLLs[] = { | |
| 65 L"%WINDIR%\\system32\\mf.dll", | |
| 66 L"%WINDIR%\\system32\\mfplat.dll", | |
| 67 L"%WINDIR%\\system32\\mfreadwrite.dll", | |
| 68 }; | |
| 69 | |
| 70 for (const wchar_t* kMfDLL : kMfDLLs) { | |
| 71 wchar_t path[MAX_PATH] = {0}; | |
| 72 ExpandEnvironmentStringsW(kMfDLL, path, arraysize(path)); | |
| 73 if (!LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH)) | |
| 74 return false; | |
| 75 } | |
| 76 return true; | |
| 77 } | |
| 78 | |
| 79 static bool PrepareVideoCaptureAttributesMediaFoundation( | |
| 80 IMFAttributes** attributes, | |
| 81 int count) { | |
| 82 InitializeMediaFoundation(); | |
| 83 | |
| 84 if (FAILED(MFCreateAttributes(attributes, count))) | |
| 85 return false; | |
| 86 | |
| 87 return SUCCEEDED( | |
| 88 (*attributes) | |
| 89 ->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, | |
| 90 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); | |
| 91 } | |
| 92 | |
| 93 static bool CreateVideoCaptureDeviceMediaFoundation(const char* sym_link, | |
| 94 IMFMediaSource** source) { | |
| 95 ScopedComPtr<IMFAttributes> attributes; | |
| 96 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 2)) | |
| 97 return false; | |
| 98 | |
| 99 attributes->SetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, | |
| 100 base::SysUTF8ToWide(sym_link).c_str()); | |
| 101 | |
| 102 return SUCCEEDED(MFCreateDeviceSource(attributes.get(), source)); | |
| 103 } | |
| 104 | |
| 105 static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices, | |
| 106 UINT32* count) { | |
| 107 ScopedComPtr<IMFAttributes> attributes; | |
| 108 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1)) | |
| 109 return false; | |
| 110 | |
| 111 return SUCCEEDED(MFEnumDeviceSources(attributes.get(), devices, count)); | |
| 112 } | |
| 113 | |
| 114 static bool IsDeviceBlackListed(const std::string& name) { | |
| 115 DCHECK_EQ(BLACKLISTED_CAMERA_MAX + 1, | |
| 116 static_cast<int>(arraysize(kBlacklistedCameraNames))); | |
| 117 for (size_t i = 0; i < arraysize(kBlacklistedCameraNames); ++i) { | |
| 118 if (base::StartsWith(name, kBlacklistedCameraNames[i], | |
| 119 base::CompareCase::INSENSITIVE_ASCII)) { | |
| 120 DVLOG(1) << "Enumerated blacklisted device: " << name; | |
| 121 UMA_HISTOGRAM_ENUMERATION("Media.VideoCapture.BlacklistedDevice", i, | |
| 122 BLACKLISTED_CAMERA_MAX + 1); | |
| 123 return true; | |
| 124 } | |
| 125 } | |
| 126 return false; | |
| 127 } | |
| 128 | |
| 129 static std::string GetDeviceModelId(const std::string& device_id) { | |
| 130 const size_t vid_prefix_size = sizeof(kVidPrefix) - 1; | |
| 131 const size_t pid_prefix_size = sizeof(kPidPrefix) - 1; | |
| 132 const size_t vid_location = device_id.find(kVidPrefix); | |
| 133 if (vid_location == std::string::npos || | |
| 134 vid_location + vid_prefix_size + kVidPidSize > device_id.size()) { | |
| 135 return std::string(); | |
| 136 } | |
| 137 const size_t pid_location = device_id.find(kPidPrefix); | |
| 138 if (pid_location == std::string::npos || | |
| 139 pid_location + pid_prefix_size + kVidPidSize > device_id.size()) { | |
| 140 return std::string(); | |
| 141 } | |
| 142 const std::string id_vendor = | |
| 143 device_id.substr(vid_location + vid_prefix_size, kVidPidSize); | |
| 144 const std::string id_product = | |
| 145 device_id.substr(pid_location + pid_prefix_size, kVidPidSize); | |
| 146 return id_vendor + ":" + id_product; | |
| 147 } | |
| 148 | |
| 149 static void GetDeviceDescriptorsDirectShow(Descriptors* device_descriptors) { | |
| 150 DCHECK(device_descriptors); | |
| 151 DVLOG(1) << __FUNCTION__; | |
| 152 | |
| 153 ScopedComPtr<ICreateDevEnum> dev_enum; | |
| 154 HRESULT hr = | |
| 155 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC); | |
| 156 if (FAILED(hr)) | |
| 157 return; | |
| 158 | |
| 159 ScopedComPtr<IEnumMoniker> enum_moniker; | |
| 160 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | |
| 161 enum_moniker.Receive(), 0); | |
| 162 // CreateClassEnumerator returns S_FALSE on some Windows OS | |
| 163 // when no camera exist. Therefore the FAILED macro can't be used. | |
| 164 if (hr != S_OK) | |
| 165 return; | |
| 166 | |
| 167 // Enumerate all video capture devices. | |
| 168 for (ScopedComPtr<IMoniker> moniker; | |
| 169 enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK; | |
| 170 moniker.Release()) { | |
| 171 ScopedComPtr<IPropertyBag> prop_bag; | |
| 172 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | |
| 173 if (FAILED(hr)) | |
| 174 continue; | |
| 175 | |
| 176 // Find the description or friendly name. | |
| 177 ScopedVariant name; | |
| 178 hr = prop_bag->Read(L"Description", name.Receive(), 0); | |
| 179 if (FAILED(hr)) | |
| 180 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); | |
| 181 | |
| 182 if (FAILED(hr) || name.type() != VT_BSTR) | |
| 183 continue; | |
| 184 | |
| 185 const std::string device_name(base::SysWideToUTF8(V_BSTR(name.ptr()))); | |
| 186 if (IsDeviceBlackListed(device_name)) | |
| 187 continue; | |
| 188 | |
| 189 name.Reset(); | |
| 190 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); | |
| 191 std::string id; | |
| 192 if (FAILED(hr) || name.type() != VT_BSTR) { | |
| 193 id = device_name; | |
| 194 } else { | |
| 195 DCHECK_EQ(name.type(), VT_BSTR); | |
| 196 id = base::SysWideToUTF8(V_BSTR(name.ptr())); | |
| 197 } | |
| 198 | |
| 199 const std::string model_id = GetDeviceModelId(id); | |
| 200 | |
| 201 device_descriptors->emplace_back(device_name, id, model_id, | |
| 202 VideoCaptureApi::WIN_DIRECT_SHOW); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 static void GetDeviceDescriptorsMediaFoundation( | |
| 207 Descriptors* device_descriptors) { | |
| 208 DVLOG(1) << " GetDeviceDescriptorsMediaFoundation"; | |
| 209 ScopedCoMem<IMFActivate*> devices; | |
| 210 UINT32 count; | |
| 211 if (!EnumerateVideoDevicesMediaFoundation(&devices, &count)) | |
| 212 return; | |
| 213 | |
| 214 for (UINT32 i = 0; i < count; ++i) { | |
| 215 ScopedCoMem<wchar_t> name; | |
| 216 UINT32 name_size; | |
| 217 HRESULT hr = devices[i]->GetAllocatedString( | |
| 218 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size); | |
| 219 if (SUCCEEDED(hr)) { | |
| 220 ScopedCoMem<wchar_t> id; | |
| 221 UINT32 id_size; | |
| 222 hr = devices[i]->GetAllocatedString( | |
| 223 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id, | |
| 224 &id_size); | |
| 225 if (SUCCEEDED(hr)) { | |
| 226 const std::string device_id = | |
| 227 base::SysWideToUTF8(std::wstring(id, id_size)); | |
| 228 const std::string model_id = GetDeviceModelId(device_id); | |
| 229 device_descriptors->emplace_back( | |
| 230 base::SysWideToUTF8(std::wstring(name, name_size)), device_id, | |
| 231 model_id, VideoCaptureApi::WIN_MEDIA_FOUNDATION); | |
| 232 } | |
| 233 } | |
| 234 DLOG_IF(ERROR, FAILED(hr)) << "GetAllocatedString failed: " | |
| 235 << logging::SystemErrorCodeToString(hr); | |
| 236 devices[i]->Release(); | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 static void GetDeviceSupportedFormatsDirectShow(const Descriptor& descriptor, | |
| 241 VideoCaptureFormats* formats) { | |
| 242 DVLOG(1) << "GetDeviceSupportedFormatsDirectShow for " | |
| 243 << descriptor.display_name; | |
| 244 ScopedComPtr<ICreateDevEnum> dev_enum; | |
| 245 HRESULT hr = | |
| 246 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC); | |
| 247 if (FAILED(hr)) | |
| 248 return; | |
| 249 | |
| 250 ScopedComPtr<IEnumMoniker> enum_moniker; | |
| 251 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | |
| 252 enum_moniker.Receive(), 0); | |
| 253 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera | |
| 254 // exists. Therefore the FAILED macro can't be used. | |
| 255 if (hr != S_OK) | |
| 256 return; | |
| 257 | |
| 258 // Walk the capture devices. No need to check for device presence again since | |
| 259 // that is anyway needed in GetDeviceFilter(). "google camera adapter" and old | |
| 260 // VFW devices are already skipped previously in GetDeviceNames() enumeration. | |
| 261 base::win::ScopedComPtr<IBaseFilter> capture_filter; | |
| 262 hr = VideoCaptureDeviceWin::GetDeviceFilter(descriptor.device_id, | |
| 263 capture_filter.Receive()); | |
| 264 if (!capture_filter.get()) { | |
| 265 DLOG(ERROR) << "Failed to create capture filter: " | |
| 266 << logging::SystemErrorCodeToString(hr); | |
| 267 return; | |
| 268 } | |
| 269 | |
| 270 base::win::ScopedComPtr<IPin> output_capture_pin( | |
| 271 VideoCaptureDeviceWin::GetPin(capture_filter.get(), PINDIR_OUTPUT, | |
| 272 PIN_CATEGORY_CAPTURE, GUID_NULL)); | |
| 273 if (!output_capture_pin.get()) { | |
| 274 DLOG(ERROR) << "Failed to get capture output pin"; | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 ScopedComPtr<IAMStreamConfig> stream_config; | |
| 279 hr = output_capture_pin.QueryInterface(stream_config.Receive()); | |
| 280 if (FAILED(hr)) { | |
| 281 DLOG(ERROR) << "Failed to get IAMStreamConfig interface from " | |
| 282 "capture device: " << logging::SystemErrorCodeToString(hr); | |
| 283 return; | |
| 284 } | |
| 285 | |
| 286 int count = 0, size = 0; | |
| 287 hr = stream_config->GetNumberOfCapabilities(&count, &size); | |
| 288 if (FAILED(hr)) { | |
| 289 DLOG(ERROR) << "GetNumberOfCapabilities failed: " | |
| 290 << logging::SystemErrorCodeToString(hr); | |
| 291 return; | |
| 292 } | |
| 293 | |
| 294 std::unique_ptr<BYTE[]> caps(new BYTE[size]); | |
| 295 for (int i = 0; i < count; ++i) { | |
| 296 VideoCaptureDeviceWin::ScopedMediaType media_type; | |
| 297 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); | |
| 298 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | |
| 299 // macros here since they'll trigger incorrectly. | |
| 300 if (hr != S_OK || !media_type.get()) { | |
| 301 DLOG(ERROR) << "GetStreamCaps failed: " | |
| 302 << logging::SystemErrorCodeToString(hr); | |
| 303 return; | |
| 304 } | |
| 305 | |
| 306 if (media_type->majortype == MEDIATYPE_Video && | |
| 307 media_type->formattype == FORMAT_VideoInfo) { | |
| 308 VideoCaptureFormat format; | |
| 309 format.pixel_format = | |
| 310 VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat( | |
| 311 media_type->subtype); | |
| 312 if (format.pixel_format == PIXEL_FORMAT_UNKNOWN) | |
| 313 continue; | |
| 314 VIDEOINFOHEADER* h = | |
| 315 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | |
| 316 format.frame_size.SetSize(h->bmiHeader.biWidth, h->bmiHeader.biHeight); | |
| 317 // Trust the frame rate from the VIDEOINFOHEADER. | |
| 318 format.frame_rate = | |
| 319 (h->AvgTimePerFrame > 0) | |
| 320 ? kSecondsToReferenceTime / static_cast<float>(h->AvgTimePerFrame) | |
| 321 : 0.0f; | |
| 322 formats->push_back(format); | |
| 323 DVLOG(1) << descriptor.display_name << " " | |
| 324 << VideoCaptureFormat::ToString(format); | |
| 325 } | |
| 326 } | |
| 327 } | |
| 328 | |
| 329 static void GetDeviceSupportedFormatsMediaFoundation( | |
| 330 const Descriptor& descriptor, | |
| 331 VideoCaptureFormats* formats) { | |
| 332 DVLOG(1) << "GetDeviceSupportedFormatsMediaFoundation for " | |
| 333 << descriptor.display_name; | |
| 334 ScopedComPtr<IMFMediaSource> source; | |
| 335 if (!CreateVideoCaptureDeviceMediaFoundation(descriptor.device_id.c_str(), | |
| 336 source.Receive())) { | |
| 337 return; | |
| 338 } | |
| 339 | |
| 340 base::win::ScopedComPtr<IMFSourceReader> reader; | |
| 341 HRESULT hr = | |
| 342 MFCreateSourceReaderFromMediaSource(source.get(), NULL, reader.Receive()); | |
| 343 if (FAILED(hr)) { | |
| 344 DLOG(ERROR) << "MFCreateSourceReaderFromMediaSource failed: " | |
| 345 << logging::SystemErrorCodeToString(hr); | |
| 346 return; | |
| 347 } | |
| 348 | |
| 349 DWORD stream_index = 0; | |
| 350 ScopedComPtr<IMFMediaType> type; | |
| 351 while (SUCCEEDED(reader->GetNativeMediaType(kFirstVideoStream, stream_index, | |
| 352 type.Receive()))) { | |
| 353 UINT32 width, height; | |
| 354 hr = MFGetAttributeSize(type.get(), MF_MT_FRAME_SIZE, &width, &height); | |
| 355 if (FAILED(hr)) { | |
| 356 DLOG(ERROR) << "MFGetAttributeSize failed: " | |
| 357 << logging::SystemErrorCodeToString(hr); | |
| 358 return; | |
| 359 } | |
| 360 VideoCaptureFormat capture_format; | |
| 361 capture_format.frame_size.SetSize(width, height); | |
| 362 | |
| 363 UINT32 numerator, denominator; | |
| 364 hr = MFGetAttributeRatio(type.get(), MF_MT_FRAME_RATE, &numerator, | |
| 365 &denominator); | |
| 366 if (FAILED(hr)) { | |
| 367 DLOG(ERROR) << "MFGetAttributeSize failed: " | |
| 368 << logging::SystemErrorCodeToString(hr); | |
| 369 return; | |
| 370 } | |
| 371 capture_format.frame_rate = | |
| 372 denominator ? static_cast<float>(numerator) / denominator : 0.0f; | |
| 373 | |
| 374 GUID type_guid; | |
| 375 hr = type->GetGUID(MF_MT_SUBTYPE, &type_guid); | |
| 376 if (FAILED(hr)) { | |
| 377 DLOG(ERROR) << "GetGUID failed: " << logging::SystemErrorCodeToString(hr); | |
| 378 return; | |
| 379 } | |
| 380 VideoCaptureDeviceMFWin::FormatFromGuid(type_guid, | |
| 381 &capture_format.pixel_format); | |
| 382 type.Release(); | |
| 383 formats->push_back(capture_format); | |
| 384 ++stream_index; | |
| 385 | |
| 386 DVLOG(1) << descriptor.display_name << " " | |
| 387 << VideoCaptureFormat::ToString(capture_format); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 // Returns true iff the current platform supports the Media Foundation API | |
| 392 // and that the DLLs are available. On Vista this API is an optional download | |
| 393 // but the API is advertised as a part of Windows 7 and onwards. However, | |
| 394 // we've seen that the required DLLs are not available in some Win7 | |
| 395 // distributions such as Windows 7 N and Windows 7 KN. | |
| 396 // static | |
| 397 bool VideoCaptureDeviceFactoryWin::PlatformSupportsMediaFoundation() { | |
| 398 // Even though the DLLs might be available on Vista, we get crashes | |
| 399 // when running our tests on the build bots. | |
| 400 if (base::win::GetVersion() < base::win::VERSION_WIN7) | |
| 401 return false; | |
| 402 | |
| 403 static bool g_dlls_available = LoadMediaFoundationDlls(); | |
| 404 return g_dlls_available; | |
| 405 } | |
| 406 | |
| 407 VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() | |
| 408 : use_media_foundation_(base::win::GetVersion() >= | |
| 409 base::win::VERSION_WIN7 && | |
| 410 base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 411 switches::kForceMediaFoundationVideoCapture)) {} | |
| 412 | |
| 413 std::unique_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::CreateDevice( | |
| 414 const Descriptor& device_descriptor) { | |
| 415 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 416 std::unique_ptr<VideoCaptureDevice> device; | |
| 417 if (device_descriptor.capture_api == VideoCaptureApi::WIN_MEDIA_FOUNDATION) { | |
| 418 DCHECK(PlatformSupportsMediaFoundation()); | |
| 419 device.reset(new VideoCaptureDeviceMFWin(device_descriptor)); | |
| 420 DVLOG(1) << " MediaFoundation Device: " << device_descriptor.display_name; | |
| 421 ScopedComPtr<IMFMediaSource> source; | |
| 422 if (!CreateVideoCaptureDeviceMediaFoundation( | |
| 423 device_descriptor.device_id.c_str(), source.Receive())) { | |
| 424 return std::unique_ptr<VideoCaptureDevice>(); | |
| 425 } | |
| 426 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) | |
| 427 device.reset(); | |
| 428 } else if (device_descriptor.capture_api == | |
| 429 VideoCaptureApi::WIN_DIRECT_SHOW) { | |
| 430 device.reset(new VideoCaptureDeviceWin(device_descriptor)); | |
| 431 DVLOG(1) << " DirectShow Device: " << device_descriptor.display_name; | |
| 432 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) | |
| 433 device.reset(); | |
| 434 } else { | |
| 435 NOTREACHED(); | |
| 436 } | |
| 437 return device; | |
| 438 } | |
| 439 | |
| 440 void VideoCaptureDeviceFactoryWin::GetDeviceDescriptors( | |
| 441 VideoCaptureDeviceDescriptors* device_descriptors) { | |
| 442 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 443 if (use_media_foundation_) | |
| 444 GetDeviceDescriptorsMediaFoundation(device_descriptors); | |
| 445 else | |
| 446 GetDeviceDescriptorsDirectShow(device_descriptors); | |
| 447 } | |
| 448 | |
| 449 void VideoCaptureDeviceFactoryWin::GetSupportedFormats( | |
| 450 const Descriptor& device, | |
| 451 VideoCaptureFormats* formats) { | |
| 452 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 453 if (use_media_foundation_) | |
| 454 GetDeviceSupportedFormatsMediaFoundation(device, formats); | |
| 455 else | |
| 456 GetDeviceSupportedFormatsDirectShow(device, formats); | |
| 457 } | |
| 458 | |
| 459 // static | |
| 460 VideoCaptureDeviceFactory* | |
| 461 VideoCaptureDeviceFactory::CreateVideoCaptureDeviceFactory( | |
| 462 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) { | |
| 463 return new VideoCaptureDeviceFactoryWin(); | |
| 464 } | |
| 465 | |
| 466 } // namespace media | |
| OLD | NEW |