Chromium Code Reviews

Side by Side Diff: media/video/capture/win/video_capture_device_factory_win.cc

Issue 510723003: Win Video Capture: add support for enumerating DirectShow WDM devices (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: using VideoCaptureDevice::Name(s) --> Name(s) Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
« no previous file with comments | « media/video/capture/video_capture_device.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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...)
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...)
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...)
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
OLDNEW
« no previous file with comments | « media/video/capture/video_capture_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine