Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(735)

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

Issue 517273004: Win Video Capture: add DirectShow WDM devices capabilities enumeration. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: perkj@s comments and suggestions Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
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"
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
OLDNEW
« no previous file with comments | « media/video/capture/video_capture_device.cc ('k') | media/video/capture/win/video_capture_device_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698