OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/video/capture/win/video_capture_device_factory_win.h" | 5 #include "media/video/capture/win/video_capture_device_factory_win.h" |
6 | 6 |
7 #include <mfapi.h> | 7 #include <mfapi.h> |
8 #include <mferror.h> | 8 #include <mferror.h> |
9 | 9 |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 | 83 |
84 static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices, | 84 static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices, |
85 UINT32* count) { | 85 UINT32* count) { |
86 ScopedComPtr<IMFAttributes> attributes; | 86 ScopedComPtr<IMFAttributes> attributes; |
87 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1)) | 87 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1)) |
88 return false; | 88 return false; |
89 | 89 |
90 return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count)); | 90 return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count)); |
91 } | 91 } |
92 | 92 |
93 static void GetDeviceNamesDirectShow(Names* device_names) { | 93 static void GetDeviceNamesDirectShow( |
| 94 const CLSID class_id, |
| 95 const Name::CaptureApiType capture_api_type, |
| 96 Names* device_names) { |
94 DCHECK(device_names); | 97 DCHECK(device_names); |
95 DVLOG(1) << " GetDeviceNamesDirectShow"; | 98 DVLOG(1) << " GetDeviceNamesDirectShow"; |
96 | 99 |
97 ScopedComPtr<ICreateDevEnum> dev_enum; | 100 ScopedComPtr<ICreateDevEnum> dev_enum; |
98 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | 101 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
99 CLSCTX_INPROC); | 102 CLSCTX_INPROC); |
100 if (FAILED(hr)) | 103 if (FAILED(hr)) |
101 return; | 104 return; |
102 | 105 |
103 static const struct{ | 106 ScopedComPtr<IEnumMoniker> enum_moniker; |
104 CLSID class_id; | 107 hr = dev_enum->CreateClassEnumerator(class_id, enum_moniker.Receive(), 0); |
105 Name::CaptureApiType capture_api_type; | 108 // CreateClassEnumerator returns S_FALSE on some Windows OS |
106 } kDirectShowFilterClasses[] = { | 109 // when no camera exist. Therefore the FAILED macro can't be used. |
107 { CLSID_VideoInputDeviceCategory, Name::DIRECT_SHOW }, | 110 if (hr != S_OK) |
108 { AM_KSCATEGORY_CROSSBAR, Name::DIRECT_SHOW_WDM} | 111 return; |
109 }; | |
110 | 112 |
| 113 // Name of a fake DirectShow filter that exist on computers with |
| 114 // GTalk installed. |
| 115 static const char kGoogleCameraAdapter[] = "google camera adapter"; |
111 | 116 |
112 device_names->clear(); | 117 // Enumerate all video capture devices. |
113 for (int class_index = 0; class_index < arraysize(kDirectShowFilterClasses); | 118 ScopedComPtr<IMoniker> moniker; |
114 ++class_index) { | 119 int index = 0; |
115 ScopedComPtr<IEnumMoniker> enum_moniker; | 120 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { |
116 hr = dev_enum->CreateClassEnumerator( | 121 ScopedComPtr<IPropertyBag> prop_bag; |
117 kDirectShowFilterClasses[class_index].class_id, | 122 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); |
118 enum_moniker.Receive(), | 123 if (FAILED(hr)) { |
119 0); | 124 moniker.Release(); |
120 // CreateClassEnumerator returns S_FALSE on some Windows OS | 125 return; |
121 // when no camera exist. Therefore the FAILED macro can't be used. | 126 } |
122 if (hr != S_OK) | |
123 continue; | |
124 | 127 |
125 // Name of a fake DirectShow filter that exist on computers with | 128 // Find the description or friendly name. |
126 // GTalk installed. | 129 ScopedVariant name; |
127 static const char kGoogleCameraAdapter[] = "google camera adapter"; | 130 hr = prop_bag->Read(L"Description", name.Receive(), 0); |
| 131 if (FAILED(hr)) |
| 132 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); |
128 | 133 |
129 // Enumerate all video capture devices. | 134 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { |
130 ScopedComPtr<IMoniker> moniker; | 135 // Ignore all VFW drivers and the special Google Camera Adapter. |
131 int index = 0; | 136 // Google Camera Adapter is not a real DirectShow camera device. |
132 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { | 137 // VFW are very old Video for Windows drivers that can not be used. |
133 ScopedComPtr<IPropertyBag> prop_bag; | 138 const wchar_t* str_ptr = V_BSTR(&name); |
134 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, | 139 const int name_length = arraysize(kGoogleCameraAdapter) - 1; |
135 prop_bag.ReceiveVoid()); | 140 |
136 if (FAILED(hr)) { | 141 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && |
137 moniker.Release(); | 142 lstrlenW(str_ptr) < name_length || |
138 continue; | 143 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, |
| 144 kGoogleCameraAdapter)))) { |
| 145 std::string id; |
| 146 std::string device_name(base::SysWideToUTF8(str_ptr)); |
| 147 name.Reset(); |
| 148 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); |
| 149 if (FAILED(hr) || name.type() != VT_BSTR) { |
| 150 id = device_name; |
| 151 } else { |
| 152 DCHECK_EQ(name.type(), VT_BSTR); |
| 153 id = base::SysWideToUTF8(V_BSTR(&name)); |
| 154 } |
| 155 device_names->push_back(Name(device_name, id, capture_api_type)); |
139 } | 156 } |
140 | |
141 // Find the description or friendly name. | |
142 ScopedVariant name; | |
143 hr = prop_bag->Read(L"Description", name.Receive(), 0); | |
144 if (FAILED(hr)) | |
145 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); | |
146 | |
147 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { | |
148 // Ignore all VFW drivers and the special Google Camera Adapter. | |
149 // Google Camera Adapter is not a real DirectShow camera device. | |
150 // VFW are very old Video for Windows drivers that can not be used. | |
151 const wchar_t* str_ptr = V_BSTR(&name); | |
152 const int name_length = arraysize(kGoogleCameraAdapter) - 1; | |
153 | |
154 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && | |
155 lstrlenW(str_ptr) < name_length || | |
156 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, | |
157 kGoogleCameraAdapter)))) { | |
158 std::string id; | |
159 std::string device_name(base::SysWideToUTF8(str_ptr)); | |
160 name.Reset(); | |
161 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); | |
162 if (FAILED(hr) || name.type() != VT_BSTR) { | |
163 id = device_name; | |
164 } else { | |
165 DCHECK_EQ(name.type(), VT_BSTR); | |
166 id = base::SysWideToUTF8(V_BSTR(&name)); | |
167 } | |
168 device_names->push_back(Name(device_name, id, | |
169 kDirectShowFilterClasses[class_index].capture_api_type)); | |
170 } | |
171 } | |
172 moniker.Release(); | |
173 } | 157 } |
| 158 moniker.Release(); |
174 } | 159 } |
175 } | 160 } |
176 | 161 |
177 static void GetDeviceNamesMediaFoundation(Names* device_names) { | 162 static void GetDeviceNamesMediaFoundation(Names* device_names) { |
178 DVLOG(1) << " GetDeviceNamesMediaFoundation"; | 163 DVLOG(1) << " GetDeviceNamesMediaFoundation"; |
179 ScopedCoMem<IMFActivate*> devices; | 164 ScopedCoMem<IMFActivate*> devices; |
180 UINT32 count; | 165 UINT32 count; |
181 if (!EnumerateVideoDevicesMediaFoundation(&devices, &count)) | 166 if (!EnumerateVideoDevicesMediaFoundation(&devices, &count)) |
182 return; | 167 return; |
183 | 168 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 return; | 200 return; |
216 | 201 |
217 ScopedComPtr<IEnumMoniker> enum_moniker; | 202 ScopedComPtr<IEnumMoniker> enum_moniker; |
218 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | 203 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, |
219 enum_moniker.Receive(), 0); | 204 enum_moniker.Receive(), 0); |
220 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera | 205 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera |
221 // exists. Therefore the FAILED macro can't be used. | 206 // exists. Therefore the FAILED macro can't be used. |
222 if (hr != S_OK) | 207 if (hr != S_OK) |
223 return; | 208 return; |
224 | 209 |
225 // Walk the capture devices. No need to check for device presence again, that | 210 // Walk the capture devices. No need to check for device presence again since |
226 // is caught in GetDeviceFilter(). "google camera adapter" and old VFW devices | 211 // that is anyway needed in GetDeviceFilter(). "google camera adapter" and old |
227 // are already skipped in the previous GetDeviceNames() enumeration. | 212 // VFW devices are already skipped previously in GetDeviceNames() enumeration. |
228 base::win::ScopedComPtr<IBaseFilter> capture_filter; | 213 base::win::ScopedComPtr<IBaseFilter> capture_filter; |
229 hr = VideoCaptureDeviceWin::GetDeviceFilter(device, | 214 hr = VideoCaptureDeviceWin::GetDeviceFilter(device.capabilities_id(), |
230 capture_filter.Receive()); | 215 capture_filter.Receive()); |
231 if (!capture_filter) { | 216 if (!capture_filter) { |
232 DLOG(ERROR) << "Failed to create capture filter: " | 217 DLOG(ERROR) << "Failed to create capture filter: " |
233 << logging::SystemErrorCodeToString(hr); | 218 << logging::SystemErrorCodeToString(hr); |
234 return; | 219 return; |
235 } | 220 } |
236 | 221 |
237 base::win::ScopedComPtr<IPin> output_capture_pin( | 222 base::win::ScopedComPtr<IPin> output_capture_pin( |
238 VideoCaptureDeviceWin::GetPin(capture_filter, | 223 VideoCaptureDeviceWin::GetPin(capture_filter, |
239 PINDIR_OUTPUT, | 224 PINDIR_OUTPUT, |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
397 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); | 382 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); |
398 ScopedComPtr<IMFMediaSource> source; | 383 ScopedComPtr<IMFMediaSource> source; |
399 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), | 384 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), |
400 source.Receive())) { | 385 source.Receive())) { |
401 return scoped_ptr<VideoCaptureDevice>(); | 386 return scoped_ptr<VideoCaptureDevice>(); |
402 } | 387 } |
403 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) | 388 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) |
404 device.reset(); | 389 device.reset(); |
405 } else { | 390 } else { |
406 DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW || | 391 DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW || |
407 device_name.capture_api_type() == Name::DIRECT_SHOW_WDM); | 392 device_name.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR); |
408 device.reset(new VideoCaptureDeviceWin(device_name)); | 393 device.reset(new VideoCaptureDeviceWin(device_name)); |
409 DVLOG(1) << " DirectShow Device: " << device_name.name(); | 394 DVLOG(1) << " DirectShow Device: " << device_name.name(); |
410 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) | 395 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) |
411 device.reset(); | 396 device.reset(); |
412 } | 397 } |
413 return device.Pass(); | 398 return device.Pass(); |
414 } | 399 } |
415 | 400 |
416 void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) { | 401 void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) { |
417 DCHECK(thread_checker_.CalledOnValidThread()); | 402 DCHECK(thread_checker_.CalledOnValidThread()); |
418 if (use_media_foundation_) | 403 if (use_media_foundation_) { |
419 GetDeviceNamesMediaFoundation(device_names); | 404 GetDeviceNamesMediaFoundation(device_names); |
420 else | 405 } else { |
421 GetDeviceNamesDirectShow(device_names); | 406 GetDeviceNamesDirectShow(CLSID_VideoInputDeviceCategory, |
| 407 Name::DIRECT_SHOW, |
| 408 device_names); |
| 409 |
| 410 Names crossbar_device_names; |
| 411 GetDeviceNamesDirectShow(AM_KSCATEGORY_CROSSBAR, |
| 412 Name::DIRECT_SHOW_WDM_CROSSBAR, |
| 413 &crossbar_device_names); |
| 414 // Search in the listed |device_names| to find a device with matching USB ID |
| 415 // to each device in |crossbar_device_names|. |
| 416 for (Names::iterator crossbar_device_it = crossbar_device_names.begin(); |
| 417 crossbar_device_it != crossbar_device_names.end(); |
| 418 ++crossbar_device_it) { |
| 419 const std::string& crossbar_device_model = crossbar_device_it->GetModel(); |
| 420 for (Names::const_iterator device_it = device_names->begin(); |
| 421 device_it != device_names->end(); ++device_it) { |
| 422 if (crossbar_device_model == device_it->GetModel()) { |
| 423 crossbar_device_it->set_capabilities_id(device_it->id()); |
| 424 device_names->push_back(*crossbar_device_it); |
| 425 break; |
| 426 } |
| 427 } |
| 428 } |
| 429 } |
422 } | 430 } |
423 | 431 |
424 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( | 432 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( |
425 const Name& device, | 433 const Name& device, |
426 VideoCaptureFormats* formats) { | 434 VideoCaptureFormats* formats) { |
427 DCHECK(thread_checker_.CalledOnValidThread()); | 435 DCHECK(thread_checker_.CalledOnValidThread()); |
428 if (use_media_foundation_) | 436 if (use_media_foundation_) |
429 GetDeviceSupportedFormatsMediaFoundation(device, formats); | 437 GetDeviceSupportedFormatsMediaFoundation(device, formats); |
430 else | 438 else |
431 GetDeviceSupportedFormatsDirectShow(device, formats); | 439 GetDeviceSupportedFormatsDirectShow(device, formats); |
432 } | 440 } |
433 | 441 |
434 } // namespace media | 442 } // namespace media |
OLD | NEW |