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" |
11 #include "base/lazy_instance.h" | 11 #include "base/lazy_instance.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/strings/sys_string_conversions.h" | 13 #include "base/strings/sys_string_conversions.h" |
14 #include "base/win/metro.h" | 14 #include "base/win/metro.h" |
15 #include "base/win/scoped_co_mem.h" | 15 #include "base/win/scoped_co_mem.h" |
16 #include "base/win/scoped_variant.h" | 16 #include "base/win/scoped_variant.h" |
17 #include "base/win/windows_version.h" | 17 #include "base/win/windows_version.h" |
18 #include "media/base/media_switches.h" | 18 #include "media/base/media_switches.h" |
19 #include "media/video/capture/win/video_capture_device_mf_win.h" | 19 #include "media/video/capture/win/video_capture_device_mf_win.h" |
20 #include "media/video/capture/win/video_capture_device_win.h" | 20 #include "media/video/capture/win/video_capture_device_win.h" |
21 | 21 |
22 using base::win::ScopedCoMem; | 22 using base::win::ScopedCoMem; |
23 using base::win::ScopedComPtr; | 23 using base::win::ScopedComPtr; |
24 using base::win::ScopedVariant; | 24 using base::win::ScopedVariant; |
25 using Name = media::VideoCaptureDevice::Name; | |
26 using Names = media::VideoCaptureDevice::Names; | |
mcasas
2014/08/28 11:53:41
Comment: since Name is a nested class inside VCD,
| |
25 | 27 |
26 namespace media { | 28 namespace media { |
27 | 29 |
28 // Lazy Instance to initialize the MediaFoundation Library. | 30 // Lazy Instance to initialize the MediaFoundation Library. |
29 class MFInitializerSingleton { | 31 class MFInitializerSingleton { |
30 public: | 32 public: |
31 MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); } | 33 MFInitializerSingleton() { MFStartup(MF_VERSION, MFSTARTUP_LITE); } |
32 ~MFInitializerSingleton() { MFShutdown(); } | 34 ~MFInitializerSingleton() { MFShutdown(); } |
33 }; | 35 }; |
34 | 36 |
(...skipping 46 matching lines...) Loading... | |
81 | 83 |
82 static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices, | 84 static bool EnumerateVideoDevicesMediaFoundation(IMFActivate*** devices, |
83 UINT32* count) { | 85 UINT32* count) { |
84 ScopedComPtr<IMFAttributes> attributes; | 86 ScopedComPtr<IMFAttributes> attributes; |
85 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1)) | 87 if (!PrepareVideoCaptureAttributesMediaFoundation(attributes.Receive(), 1)) |
86 return false; | 88 return false; |
87 | 89 |
88 return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count)); | 90 return SUCCEEDED(MFEnumDeviceSources(attributes, devices, count)); |
89 } | 91 } |
90 | 92 |
91 static void GetDeviceNamesDirectShow(VideoCaptureDevice::Names* device_names) { | 93 static void GetDeviceNamesDirectShow(Names* device_names) { |
92 DCHECK(device_names); | 94 DCHECK(device_names); |
93 DVLOG(1) << " GetDeviceNamesDirectShow"; | 95 DVLOG(1) << " GetDeviceNamesDirectShow"; |
94 | 96 |
95 ScopedComPtr<ICreateDevEnum> dev_enum; | 97 ScopedComPtr<ICreateDevEnum> dev_enum; |
96 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | 98 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
97 CLSCTX_INPROC); | 99 CLSCTX_INPROC); |
98 if (FAILED(hr)) | 100 if (FAILED(hr)) |
99 return; | 101 return; |
100 | 102 |
101 ScopedComPtr<IEnumMoniker> enum_moniker; | 103 static const struct{ |
102 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | 104 CLSID class_id; |
103 enum_moniker.Receive(), 0); | 105 Name::CaptureApiType capture_api_type; |
104 // CreateClassEnumerator returns S_FALSE on some Windows OS | 106 } kDirectShowFilterClasses[] = { |
105 // when no camera exist. Therefore the FAILED macro can't be used. | 107 { CLSID_VideoInputDeviceCategory, Name::DIRECT_SHOW }, |
106 if (hr != S_OK) | 108 { AM_KSCATEGORY_CROSSBAR, Name::DIRECT_SHOW_WDM} |
107 return; | 109 }; |
110 | |
108 | 111 |
109 device_names->clear(); | 112 device_names->clear(); |
113 for (int class_index = 0; class_index < arraysize(kDirectShowFilterClasses); | |
114 ++class_index) { | |
115 ScopedComPtr<IEnumMoniker> enum_moniker; | |
116 hr = dev_enum->CreateClassEnumerator( | |
117 kDirectShowFilterClasses[class_index].class_id, | |
118 enum_moniker.Receive(), | |
119 0); | |
120 // CreateClassEnumerator returns S_FALSE on some Windows OS | |
121 // when no camera exist. Therefore the FAILED macro can't be used. | |
122 if (hr != S_OK) | |
123 continue; | |
110 | 124 |
111 // Name of a fake DirectShow filter that exist on computers with | 125 // Name of a fake DirectShow filter that exist on computers with |
112 // GTalk installed. | 126 // GTalk installed. |
113 static const char kGoogleCameraAdapter[] = "google camera adapter"; | 127 static const char kGoogleCameraAdapter[] = "google camera adapter"; |
114 | 128 |
115 // Enumerate all video capture devices. | 129 // Enumerate all video capture devices. |
116 ScopedComPtr<IMoniker> moniker; | 130 ScopedComPtr<IMoniker> moniker; |
117 int index = 0; | 131 int index = 0; |
118 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { | 132 while (enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK) { |
119 ScopedComPtr<IPropertyBag> prop_bag; | 133 ScopedComPtr<IPropertyBag> prop_bag; |
120 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | 134 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, |
121 if (FAILED(hr)) { | 135 prop_bag.ReceiveVoid()); |
136 if (FAILED(hr)) { | |
137 moniker.Release(); | |
138 continue; | |
139 } | |
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 } | |
122 moniker.Release(); | 172 moniker.Release(); |
123 continue; | |
124 } | 173 } |
125 | |
126 // Find the description or friendly name. | |
127 ScopedVariant name; | |
128 hr = prop_bag->Read(L"Description", name.Receive(), 0); | |
129 if (FAILED(hr)) | |
130 hr = prop_bag->Read(L"FriendlyName", name.Receive(), 0); | |
131 | |
132 if (SUCCEEDED(hr) && name.type() == VT_BSTR) { | |
133 // Ignore all VFW drivers and the special Google Camera Adapter. | |
134 // Google Camera Adapter is not a real DirectShow camera device. | |
135 // VFW are very old Video for Windows drivers that can not be used. | |
136 const wchar_t* str_ptr = V_BSTR(&name); | |
137 const int name_length = arraysize(kGoogleCameraAdapter) - 1; | |
138 | |
139 if ((wcsstr(str_ptr, L"(VFW)") == NULL) && | |
140 lstrlenW(str_ptr) < name_length || | |
141 (!(LowerCaseEqualsASCII(str_ptr, str_ptr + name_length, | |
142 kGoogleCameraAdapter)))) { | |
143 std::string id; | |
144 std::string device_name(base::SysWideToUTF8(str_ptr)); | |
145 name.Reset(); | |
146 hr = prop_bag->Read(L"DevicePath", name.Receive(), 0); | |
147 if (FAILED(hr) || name.type() != VT_BSTR) { | |
148 id = device_name; | |
149 } else { | |
150 DCHECK_EQ(name.type(), VT_BSTR); | |
151 id = base::SysWideToUTF8(V_BSTR(&name)); | |
152 } | |
153 | |
154 device_names->push_back(VideoCaptureDevice::Name(device_name, id, | |
155 VideoCaptureDevice::Name::DIRECT_SHOW)); | |
156 } | |
157 } | |
158 moniker.Release(); | |
159 } | 174 } |
160 } | 175 } |
161 | 176 |
162 static void GetDeviceNamesMediaFoundation( | 177 static void GetDeviceNamesMediaFoundation(Names* device_names) { |
163 VideoCaptureDevice::Names* device_names) { | |
164 DVLOG(1) << " GetDeviceNamesMediaFoundation"; | 178 DVLOG(1) << " GetDeviceNamesMediaFoundation"; |
165 ScopedCoMem<IMFActivate*> devices; | 179 ScopedCoMem<IMFActivate*> devices; |
166 UINT32 count; | 180 UINT32 count; |
167 if (!EnumerateVideoDevicesMediaFoundation(&devices, &count)) | 181 if (!EnumerateVideoDevicesMediaFoundation(&devices, &count)) |
168 return; | 182 return; |
169 | 183 |
170 for (UINT32 i = 0; i < count; ++i) { | 184 for (UINT32 i = 0; i < count; ++i) { |
171 ScopedCoMem<wchar_t> name; | 185 ScopedCoMem<wchar_t> name; |
172 UINT32 name_size; | 186 UINT32 name_size; |
173 HRESULT hr = devices[i]->GetAllocatedString( | 187 HRESULT hr = devices[i]->GetAllocatedString( |
174 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size); | 188 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &name, &name_size); |
175 if (SUCCEEDED(hr)) { | 189 if (SUCCEEDED(hr)) { |
176 ScopedCoMem<wchar_t> id; | 190 ScopedCoMem<wchar_t> id; |
177 UINT32 id_size; | 191 UINT32 id_size; |
178 hr = devices[i]->GetAllocatedString( | 192 hr = devices[i]->GetAllocatedString( |
179 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id, | 193 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &id, |
180 &id_size); | 194 &id_size); |
181 if (SUCCEEDED(hr)) { | 195 if (SUCCEEDED(hr)) { |
182 device_names->push_back(VideoCaptureDevice::Name( | 196 device_names->push_back(Name( |
183 base::SysWideToUTF8(std::wstring(name, name_size)), | 197 base::SysWideToUTF8(std::wstring(name, name_size)), |
184 base::SysWideToUTF8(std::wstring(id, id_size)), | 198 base::SysWideToUTF8(std::wstring(id, id_size)), |
185 VideoCaptureDevice::Name::MEDIA_FOUNDATION)); | 199 Name::MEDIA_FOUNDATION)); |
186 } | 200 } |
187 } | 201 } |
188 if (FAILED(hr)) | 202 if (FAILED(hr)) |
189 DLOG(WARNING) << "GetAllocatedString failed: " << std::hex << hr; | 203 DLOG(WARNING) << "GetAllocatedString failed: " << std::hex << hr; |
190 devices[i]->Release(); | 204 devices[i]->Release(); |
191 } | 205 } |
192 } | 206 } |
193 | 207 |
194 static void GetDeviceSupportedFormatsDirectShow( | 208 static void GetDeviceSupportedFormatsDirectShow(const Name& device, |
195 const VideoCaptureDevice::Name& device, | 209 VideoCaptureFormats* formats) { |
196 VideoCaptureFormats* formats) { | |
197 DVLOG(1) << "GetDeviceSupportedFormatsDirectShow for " << device.name(); | 210 DVLOG(1) << "GetDeviceSupportedFormatsDirectShow for " << device.name(); |
198 ScopedComPtr<ICreateDevEnum> dev_enum; | 211 ScopedComPtr<ICreateDevEnum> dev_enum; |
199 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | 212 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
200 CLSCTX_INPROC); | 213 CLSCTX_INPROC); |
201 if (FAILED(hr)) | 214 if (FAILED(hr)) |
202 return; | 215 return; |
203 | 216 |
204 ScopedComPtr<IEnumMoniker> enum_moniker; | 217 ScopedComPtr<IEnumMoniker> enum_moniker; |
205 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | 218 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, |
206 enum_moniker.Receive(), 0); | 219 enum_moniker.Receive(), 0); |
(...skipping 66 matching lines...) Loading... | |
273 0.0f; | 286 0.0f; |
274 formats->push_back(format); | 287 formats->push_back(format); |
275 DVLOG(1) << device.name() << " resolution: " | 288 DVLOG(1) << device.name() << " resolution: " |
276 << format.frame_size.ToString() << ", fps: " << format.frame_rate | 289 << format.frame_size.ToString() << ", fps: " << format.frame_rate |
277 << ", pixel format: " << format.pixel_format; | 290 << ", pixel format: " << format.pixel_format; |
278 } | 291 } |
279 } | 292 } |
280 } | 293 } |
281 | 294 |
282 static void GetDeviceSupportedFormatsMediaFoundation( | 295 static void GetDeviceSupportedFormatsMediaFoundation( |
283 const VideoCaptureDevice::Name& device, | 296 const Name& device, |
284 VideoCaptureFormats* formats) { | 297 VideoCaptureFormats* formats) { |
285 DVLOG(1) << "GetDeviceSupportedFormatsMediaFoundation for " << device.name(); | 298 DVLOG(1) << "GetDeviceSupportedFormatsMediaFoundation for " << device.name(); |
286 ScopedComPtr<IMFMediaSource> source; | 299 ScopedComPtr<IMFMediaSource> source; |
287 if (!CreateVideoCaptureDeviceMediaFoundation(device.id().c_str(), | 300 if (!CreateVideoCaptureDeviceMediaFoundation(device.id().c_str(), |
288 source.Receive())) { | 301 source.Receive())) { |
289 return; | 302 return; |
290 } | 303 } |
291 | 304 |
292 base::win::ScopedComPtr<IMFSourceReader> reader; | 305 base::win::ScopedComPtr<IMFSourceReader> reader; |
293 HRESULT hr = | 306 HRESULT hr = |
(...skipping 70 matching lines...) Loading... | |
364 // 8 in non-Metro mode. | 377 // 8 in non-Metro mode. |
365 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 378 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
366 use_media_foundation_ = (base::win::IsMetroProcess() && | 379 use_media_foundation_ = (base::win::IsMetroProcess() && |
367 !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) || | 380 !cmd_line->HasSwitch(switches::kForceDirectShowVideoCapture)) || |
368 (base::win::GetVersion() >= base::win::VERSION_WIN7 && | 381 (base::win::GetVersion() >= base::win::VERSION_WIN7 && |
369 cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture)); | 382 cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture)); |
370 } | 383 } |
371 | 384 |
372 | 385 |
373 scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create( | 386 scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create( |
374 const VideoCaptureDevice::Name& device_name) { | 387 const Name& device_name) { |
375 DCHECK(thread_checker_.CalledOnValidThread()); | 388 DCHECK(thread_checker_.CalledOnValidThread()); |
376 scoped_ptr<VideoCaptureDevice> device; | 389 scoped_ptr<VideoCaptureDevice> device; |
377 if (device_name.capture_api_type() == | 390 if (device_name.capture_api_type() == Name::MEDIA_FOUNDATION) { |
378 VideoCaptureDevice::Name::MEDIA_FOUNDATION) { | |
379 DCHECK(PlatformSupportsMediaFoundation()); | 391 DCHECK(PlatformSupportsMediaFoundation()); |
380 device.reset(new VideoCaptureDeviceMFWin(device_name)); | 392 device.reset(new VideoCaptureDeviceMFWin(device_name)); |
381 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); | 393 DVLOG(1) << " MediaFoundation Device: " << device_name.name(); |
382 ScopedComPtr<IMFMediaSource> source; | 394 ScopedComPtr<IMFMediaSource> source; |
383 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), | 395 if (!CreateVideoCaptureDeviceMediaFoundation(device_name.id().c_str(), |
384 source.Receive())) { | 396 source.Receive())) { |
385 return scoped_ptr<VideoCaptureDevice>(); | 397 return scoped_ptr<VideoCaptureDevice>(); |
386 } | 398 } |
387 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) | 399 if (!static_cast<VideoCaptureDeviceMFWin*>(device.get())->Init(source)) |
388 device.reset(); | 400 device.reset(); |
389 } else { | 401 } else { |
390 DCHECK_EQ(device_name.capture_api_type(), | 402 DCHECK(device_name.capture_api_type() == Name::DIRECT_SHOW || |
391 VideoCaptureDevice::Name::DIRECT_SHOW); | 403 device_name.capture_api_type() == Name::DIRECT_SHOW_WDM); |
392 device.reset(new VideoCaptureDeviceWin(device_name)); | 404 device.reset(new VideoCaptureDeviceWin(device_name)); |
393 DVLOG(1) << " DirectShow Device: " << device_name.name(); | 405 DVLOG(1) << " DirectShow Device: " << device_name.name(); |
394 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) | 406 if (!static_cast<VideoCaptureDeviceWin*>(device.get())->Init()) |
395 device.reset(); | 407 device.reset(); |
396 } | 408 } |
397 return device.Pass(); | 409 return device.Pass(); |
398 } | 410 } |
399 | 411 |
400 void VideoCaptureDeviceFactoryWin::GetDeviceNames( | 412 void VideoCaptureDeviceFactoryWin::GetDeviceNames(Names* device_names) { |
401 VideoCaptureDevice::Names* device_names) { | |
402 DCHECK(thread_checker_.CalledOnValidThread()); | 413 DCHECK(thread_checker_.CalledOnValidThread()); |
403 if (use_media_foundation_) | 414 if (use_media_foundation_) |
404 GetDeviceNamesMediaFoundation(device_names); | 415 GetDeviceNamesMediaFoundation(device_names); |
405 else | 416 else |
406 GetDeviceNamesDirectShow(device_names); | 417 GetDeviceNamesDirectShow(device_names); |
407 } | 418 } |
408 | 419 |
409 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( | 420 void VideoCaptureDeviceFactoryWin::GetDeviceSupportedFormats( |
410 const VideoCaptureDevice::Name& device, | 421 const Name& device, |
411 VideoCaptureFormats* formats) { | 422 VideoCaptureFormats* formats) { |
412 DCHECK(thread_checker_.CalledOnValidThread()); | 423 DCHECK(thread_checker_.CalledOnValidThread()); |
413 if (use_media_foundation_) | 424 if (use_media_foundation_) |
414 GetDeviceSupportedFormatsMediaFoundation(device, formats); | 425 GetDeviceSupportedFormatsMediaFoundation(device, formats); |
415 else | 426 else |
416 GetDeviceSupportedFormatsDirectShow(device, formats); | 427 GetDeviceSupportedFormatsDirectShow(device, formats); |
417 } | 428 } |
418 | 429 |
419 } // namespace media | 430 } // namespace media |
OLD | NEW |