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 DVLOG(2) << "Failed to create capture filter."; | 217 DVLOG(2) << "Failed to create capture filter." ; |
233 return; | 218 return; |
234 } | 219 } |
235 | 220 |
236 base::win::ScopedComPtr<IPin> output_capture_pin( | 221 base::win::ScopedComPtr<IPin> output_capture_pin( |
237 VideoCaptureDeviceWin::GetPin(capture_filter, | 222 VideoCaptureDeviceWin::GetPin(capture_filter, |
238 PINDIR_OUTPUT, | 223 PINDIR_OUTPUT, |
239 PIN_CATEGORY_CAPTURE)); | 224 PIN_CATEGORY_CAPTURE)); |
240 if (!output_capture_pin) { | 225 if (!output_capture_pin) { |
241 DVLOG(2) << "Failed to get capture output pin"; | 226 DVLOG(2) << "Failed to get capture output pin"; |
242 return; | 227 return; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
390 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); | 375 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); |
391 ScopedComPtr<IMFMediaSource> source; | 376 ScopedComPtr<IMFMediaSource> source; |
392 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), | 377 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), |
393 source.Receive())) { | 378 source.Receive())) { |
394 return scoped_ptr<VideoCaptureDevice>(); | 379 return scoped_ptr<VideoCaptureDevice>(); |
395 } | 380 } |
396 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) | 381 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) |
397 device.reset(); | 382 device.reset(); |
398 } else { | 383 } else { |
399 DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW || | 384 DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW || |
400 device_name.capture_api_type() == Name::DIRECT_SHOW_WDM); | 385 device_name.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR); |
401 device.reset(new VideoCaptureDeviceWin(device_name)); | 386 device.reset(new VideoCaptureDeviceWin(device_name)); |
402 DVLOG(1) << " DirectShow Device: " << device_name.name(); | 387 DVLOG(1) << " DirectShow Device: " << device_name.name(); |
403 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) | 388 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) |
404 device.reset(); | 389 device.reset(); |
405 } | 390 } |
406 return device.Pass(); | 391 return device.Pass(); |
407 } | 392 } |
408 | 393 |
409 void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) { | 394 void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) { |
410 DCHECK(thread_checker_.CalledOnValidThread()); | 395 DCHECK(thread_checker_.CalledOnValidThread()); |
411 if (use_media_foundation_) | 396 if (use_media_foundation_) { |
412 GetDeviceNamesMediaFoundation(device_names); | 397 GetDeviceNamesMediaFoundation(device_names); |
413 else | 398 } else { |
414 GetDeviceNamesDirectShow(device_names); | 399 GetDeviceNamesDirectShow(CLSID_VideoInputDeviceCategory, |
400 Name::DIRECT_SHOW, | |
401 device_names); | |
402 | |
403 Names crossbar_device_names; | |
404 GetDeviceNamesDirectShow(AM_KSCATEGORY_CROSSBAR, | |
405 Name::DIRECT_SHOW_WDM_CROSSBAR, | |
406 &crossbar_device_names); | |
407 // Search in the listed |device_names| to find a device with matching USB ID | |
408 // to each device in |crossbar_device_names|. | |
409 for (Names::iterator crossbar_device_it = crossbar_device_names.begin(); | |
410 crossbar_device_it != crossbar_device_names.end(); | |
perkj_chrome
2014/09/03 08:42:41
indentation
mcasas
2014/09/03 09:51:06
Done.
| |
411 ++crossbar_device_it) { | |
412 const std::string& crossbar_device_model = crossbar_device_it->GetModel(); | |
413 for (Names::const_iterator device_it = device_names->begin(); | |
414 device_it != device_names->end(); ++device_it) { | |
perkj_chrome
2014/09/03 08:42:41
indentation
mcasas
2014/09/03 09:51:06
Done.
| |
415 if (crossbar_device_model.compare(device_it->GetModel()) == 0) { | |
perkj_chrome
2014/09/03 08:42:41
prefer if crossbar_device_model == device_it->GetM
mcasas
2014/09/03 09:51:06
Done.
| |
416 crossbar_device_it->set_capabilities_id(device_it->id()); | |
417 device_names->push_back(*crossbar_device_it); | |
418 break; | |
419 } | |
420 } | |
421 } | |
422 } | |
415 } | 423 } |
416 | 424 |
417 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( | 425 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( |
418 const Name& device, | 426 const Name& device, |
419 VideoCaptureFormats* formats) { | 427 VideoCaptureFormats* formats) { |
420 DCHECK(thread_checker_.CalledOnValidThread()); | 428 DCHECK(thread_checker_.CalledOnValidThread()); |
421 if (use_media_foundation_) | 429 if (use_media_foundation_) |
422 GetDeviceSupportedFormatsMediaFoundation(device, formats); | 430 GetDeviceSupportedFormatsMediaFoundation(device, formats); |
423 else | 431 else |
424 GetDeviceSupportedFormatsDirectShow(device, formats); | 432 GetDeviceSupportedFormatsDirectShow(device, formats); |
425 } | 433 } |
426 | 434 |
427 } // namespace media | 435 } // namespace media |
OLD | NEW |