OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_win.h" | 5 #include "media/video/capture/win/video_capture_device_win.h" |
6 | 6 |
7 #include <ks.h> | 7 #include <ks.h> |
8 #include <ksmedia.h> | 8 #include <ksmedia.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 #include <list> | 11 #include <list> |
12 | 12 |
13 #include "base/strings/string_tokenizer.h" | |
13 #include "base/strings/sys_string_conversions.h" | 14 #include "base/strings/sys_string_conversions.h" |
14 #include "base/win/scoped_co_mem.h" | 15 #include "base/win/scoped_co_mem.h" |
15 #include "base/win/scoped_variant.h" | 16 #include "base/win/scoped_variant.h" |
16 #include "media/video/capture/win/video_capture_device_mf_win.h" | 17 #include "media/video/capture/win/video_capture_device_mf_win.h" |
17 | 18 |
18 using base::win::ScopedCoMem; | 19 using base::win::ScopedCoMem; |
19 using base::win::ScopedComPtr; | 20 using base::win::ScopedComPtr; |
20 using base::win::ScopedVariant; | 21 using base::win::ScopedVariant; |
21 | 22 |
22 namespace media { | 23 namespace media { |
23 | 24 |
24 // Finds and creates a DirectShow Video Capture filter matching the device_name. | 25 // Tries to find a |device_id| of class |device_class_id|. For this, it |
26 // enumerates all system devices of the given class and does a string comparison | |
27 // of its |property_name| tag. This comparison can be exact or substring-wise | |
28 // depending on |exact_name_comparison|. If such a device is found, a moniker | |
29 // to it is returned. | |
25 // static | 30 // static |
26 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id, | 31 ScopedComPtr<IMoniker> FindDeviceAndReturnMoniker(const std::string& device_id, |
27 IBaseFilter** filter) { | 32 const CLSID device_class_id, |
28 DCHECK(filter); | 33 const wchar_t* property_name, |
34 bool exact_name_comparison) { | |
29 | 35 |
36 ScopedComPtr<IMoniker> moniker; | |
30 ScopedComPtr<ICreateDevEnum> dev_enum; | 37 ScopedComPtr<ICreateDevEnum> dev_enum; |
31 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, | 38 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, |
32 CLSCTX_INPROC); | 39 CLSCTX_INPROC); |
40 DPLOG_IF(ERROR, FAILED(hr)) << "Create SystemDeviceEnum"; | |
33 if (FAILED(hr)) | 41 if (FAILED(hr)) |
34 return hr; | 42 return moniker; |
35 | 43 |
36 ScopedComPtr<IEnumMoniker> enum_moniker; | 44 ScopedComPtr<IEnumMoniker> enum_moniker; |
37 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, | 45 hr = dev_enum->CreateClassEnumerator(device_class_id, |
38 enum_moniker.Receive(), 0); | 46 enum_moniker.Receive(), 0); |
39 // CreateClassEnumerator returns S_FALSE on some Windows OS | 47 // CreateClassEnumerator returns S_FALSE on some Windows OS when no camera |
40 // when no camera exist. Therefore the FAILED macro can't be used. | 48 // exist. Therefore the FAILED macro can't be used. |
49 DPLOG_IF(ERROR, hr != S_OK) << "CreateClassEnumerator"; | |
41 if (hr != S_OK) | 50 if (hr != S_OK) |
42 return NULL; | 51 return moniker; |
43 | 52 |
44 ScopedComPtr<IMoniker> moniker; | |
45 ScopedComPtr<IBaseFilter> capture_filter; | |
46 DWORD fetched = 0; | 53 DWORD fetched = 0; |
47 while (enum_moniker->Next(1, moniker.Receive(), &fetched) == S_OK) { | 54 while (enum_moniker->Next(1, moniker.Receive(), &fetched) == S_OK) { |
48 ScopedComPtr<IPropertyBag> prop_bag; | 55 ScopedComPtr<IPropertyBag> prop_bag; |
49 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); | 56 hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, prop_bag.ReceiveVoid()); |
50 if (FAILED(hr)) { | 57 if (FAILED(hr)) { |
51 moniker.Release(); | 58 moniker.Release(); |
52 continue; | 59 continue; |
53 } | 60 } |
54 | 61 |
55 // Find the device via DevicePath, Description or FriendlyName, whichever is | |
56 // available first. | |
57 static const wchar_t* kPropertyNames[] = { | |
58 L"DevicePath", L"Description", L"FriendlyName" | |
59 }; | |
60 ScopedVariant name; | 62 ScopedVariant name; |
61 for (size_t i = 0; | 63 prop_bag->Read(property_name, name.Receive(), 0); |
62 i < arraysize(kPropertyNames) && name.type() != VT_BSTR; ++i) { | 64 |
63 prop_bag->Read(kPropertyNames[i], name.Receive(), 0); | |
64 } | |
65 if (name.type() == VT_BSTR) { | 65 if (name.type() == VT_BSTR) { |
66 std::string device_path(base::SysWideToUTF8(V_BSTR(&name))); | 66 std::string device_path(base::SysWideToUTF8(V_BSTR(&name))); |
67 if (device_path.compare(device_id) == 0) { | 67 if ((exact_name_comparison && device_path == device_id) || |
68 // We have found the requested device | 68 (!exact_name_comparison && |
69 hr = moniker->BindToObject(0, 0, IID_IBaseFilter, | 69 device_path.find(device_id) != std::string::npos)) { |
70 capture_filter.ReceiveVoid()); | 70 return moniker; |
71 DLOG_IF(ERROR, FAILED(hr)) << "Failed to bind camera filter: " | |
72 << logging::SystemErrorCodeToString(hr); | |
73 break; | |
74 } | 71 } |
75 } | 72 } |
76 moniker.Release(); | 73 moniker.Release(); |
77 } | 74 } |
75 return moniker; | |
76 } | |
78 | 77 |
79 *filter = capture_filter.Detach(); | 78 // Finds and creates a DirectShow Video Capture filter matching the device_name. |
perkj_chrome
2014/09/09 07:54:43
|device_id|
mcasas
2014/09/09 08:22:26
Done.
| |
80 if (!*filter && SUCCEEDED(hr)) | 79 // |class_id| is usually CLSID_VideoInputDeviceCategory for standard DirectShow |
81 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | 80 // device but might also be AM_KSCATEGORY_CAPTURE or AM_KSCATEGORY_CROSSBAR, to |
perkj_chrome
2014/09/08 13:32:11
nit devices
mcasas
2014/09/09 08:22:26
Done.
| |
81 // enumerate WDM capture devices or WDM crossbars, respectively. | |
82 // static | |
83 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id, | |
84 const CLSID device_class_id, | |
85 IBaseFilter** filter) { | |
86 DCHECK(filter); | |
87 const bool kExactNameComparison = true; | |
88 ScopedComPtr<IMoniker> moniker; | |
82 | 89 |
83 return hr; | 90 static const wchar_t* kPropertyNames[] = { |
91 L"DevicePath", L"Description", L"FriendlyName" | |
92 }; | |
93 for (size_t i = 0; i < arraysize(kPropertyNames); ++i) { | |
94 moniker = FindDeviceAndReturnMoniker(device_id, device_class_id, | |
perkj_chrome
2014/09/08 13:32:11
It feels wrong look in the Description and friendl
mcasas
2014/09/09 08:22:26
This loop looks for a device by DevicePath, then D
perkj_chrome
2014/09/09 10:51:08
Acknowledged.
| |
95 kPropertyNames[i], kExactNameComparison); | |
96 if (!moniker) | |
97 continue; | |
98 ScopedComPtr<IBaseFilter> capture_filter; | |
99 HRESULT hr = moniker->BindToObject(0, 0, IID_IBaseFilter, | |
100 capture_filter.ReceiveVoid()); | |
101 *filter = capture_filter.Detach(); | |
102 if (!*filter && SUCCEEDED(hr)) | |
103 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); | |
104 return hr; | |
105 } | |
106 DLOG(ERROR) << "Failed to find device " << device_id; | |
107 return E_FAIL; | |
84 } | 108 } |
85 | 109 |
86 // Check if a Pin matches a category. | 110 // Check if a Pin matches a category. |
87 // static | 111 // static |
88 bool VideoCaptureDeviceWin::PinMatchesCategory(IPin* pin, REFGUID category) { | 112 bool VideoCaptureDeviceWin::PinMatchesCategory(IPin* pin, REFGUID category) { |
89 DCHECK(pin); | 113 DCHECK(pin); |
90 bool found = false; | 114 bool found = false; |
91 ScopedComPtr<IKsPropertySet> ks_property; | 115 ScopedComPtr<IKsPropertySet> ks_property; |
92 HRESULT hr = ks_property.QueryFrom(pin); | 116 HRESULT hr = ks_property.QueryFrom(pin); |
93 if (SUCCEEDED(hr)) { | 117 if (SUCCEEDED(hr)) { |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
211 if (sink_filter_) { | 235 if (sink_filter_) { |
212 graph_builder_->RemoveFilter(sink_filter_); | 236 graph_builder_->RemoveFilter(sink_filter_); |
213 sink_filter_ = NULL; | 237 sink_filter_ = NULL; |
214 } | 238 } |
215 | 239 |
216 if (capture_filter_) | 240 if (capture_filter_) |
217 graph_builder_->RemoveFilter(capture_filter_); | 241 graph_builder_->RemoveFilter(capture_filter_); |
218 | 242 |
219 if (mjpg_filter_) | 243 if (mjpg_filter_) |
220 graph_builder_->RemoveFilter(mjpg_filter_); | 244 graph_builder_->RemoveFilter(mjpg_filter_); |
245 | |
246 if(crossbar_filter_) | |
247 graph_builder_->RemoveFilter(crossbar_filter_); | |
221 } | 248 } |
222 } | 249 } |
223 | 250 |
224 bool VideoCaptureDeviceWin::Init() { | 251 bool VideoCaptureDeviceWin::Init() { |
225 DCHECK(CalledOnValidThread()); | 252 DCHECK(CalledOnValidThread()); |
226 HRESULT hr = GetDeviceFilter(device_name_.id(), capture_filter_.Receive()); | 253 HRESULT hr; |
254 | |
255 if (device_name_.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR) { | |
256 hr = InstantiateWDMFiltersAndPins(); | |
257 } else { | |
258 hr = GetDeviceFilter(device_name_.id(), CLSID_VideoInputDeviceCategory, | |
259 capture_filter_.Receive()); | |
260 } | |
227 if (!capture_filter_) { | 261 if (!capture_filter_) { |
228 DLOG(ERROR) << "Failed to create capture filter: " | 262 DVLOG(2) << "Failed to create capture filter."; |
229 << logging::SystemErrorCodeToString(hr); | |
230 return false; | 263 return false; |
231 } | 264 } |
232 | 265 |
233 output_capture_pin_ = | 266 output_capture_pin_ = |
234 GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE); | 267 GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE); |
235 if (!output_capture_pin_) { | 268 if (!output_capture_pin_) { |
236 DLOG(ERROR) << "Failed to get capture output pin"; | 269 DVLOG(2) << "Failed to get capture output pin"; |
237 return false; | 270 return false; |
238 } | 271 } |
239 | 272 |
240 // Create the sink filter used for receiving Captured frames. | 273 // Create the sink filter used for receiving Captured frames. |
241 sink_filter_ = new SinkFilter(this); | 274 sink_filter_ = new SinkFilter(this); |
242 if (sink_filter_ == NULL) { | 275 if (sink_filter_ == NULL) { |
243 DLOG(ERROR) << "Failed to create send filter"; | 276 DVLOG(2) << "Failed to create send filter"; |
244 return false; | 277 return false; |
245 } | 278 } |
246 | 279 |
247 input_sink_pin_ = sink_filter_->GetPin(0); | 280 input_sink_pin_ = sink_filter_->GetPin(0); |
248 | 281 |
249 hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL, | 282 hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL, |
250 CLSCTX_INPROC_SERVER); | 283 CLSCTX_INPROC_SERVER); |
251 if (FAILED(hr)) { | 284 if (FAILED(hr)) { |
252 DLOG(ERROR) << "Failed to create graph builder: " | 285 DVLOG(2) << "Failed to create graph builder."; |
253 << logging::SystemErrorCodeToString(hr); | |
254 return false; | 286 return false; |
255 } | 287 } |
256 | 288 |
257 hr = graph_builder_.QueryInterface(media_control_.Receive()); | 289 hr = graph_builder_.QueryInterface(media_control_.Receive()); |
258 if (FAILED(hr)) { | 290 if (FAILED(hr)) { |
259 DLOG(ERROR) << "Failed to create media control builder: " | 291 DVLOG(2) << "Failed to create media control builder."; |
260 << logging::SystemErrorCodeToString(hr); | |
261 return false; | 292 return false; |
262 } | 293 } |
263 | 294 |
264 hr = graph_builder_->AddFilter(capture_filter_, NULL); | 295 hr = graph_builder_->AddFilter(capture_filter_, NULL); |
265 if (FAILED(hr)) { | 296 if (FAILED(hr)) { |
266 DLOG(ERROR) << "Failed to add the capture device to the graph: " | 297 DVLOG(2) << "Failed to add the capture device to the graph."; |
267 << logging::SystemErrorCodeToString(hr); | 298 return false; |
299 } | |
300 | |
301 if (device_name_.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR && | |
302 FAILED(AddWDMCrossbarFilterToGraphAndConnect())) { | |
303 DVLOG(2)<< "Failed to add/connect the WDM Crossbar filter to the graph."; | |
268 return false; | 304 return false; |
269 } | 305 } |
270 | 306 |
271 hr = graph_builder_->AddFilter(sink_filter_, NULL); | 307 hr = graph_builder_->AddFilter(sink_filter_, NULL); |
272 if (FAILED(hr)) { | 308 if (FAILED(hr)) { |
273 DLOG(ERROR) << "Failed to add the send filter to the graph: " | 309 DVLOG(2)<< "Failed to add the send filter to the graph."; |
274 << logging::SystemErrorCodeToString(hr); | |
275 return false; | 310 return false; |
276 } | 311 } |
277 | 312 |
278 return CreateCapabilityMap(); | 313 return CreateCapabilityMap(); |
279 } | 314 } |
280 | 315 |
281 void VideoCaptureDeviceWin::AllocateAndStart( | 316 void VideoCaptureDeviceWin::AllocateAndStart( |
282 const VideoCaptureParams& params, | 317 const VideoCaptureParams& params, |
283 scoped_ptr<VideoCaptureDevice::Client> client) { | 318 scoped_ptr<VideoCaptureDevice::Client> client) { |
284 DCHECK(CalledOnValidThread()); | 319 DCHECK(CalledOnValidThread()); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
416 } | 451 } |
417 | 452 |
418 graph_builder_->Disconnect(output_capture_pin_); | 453 graph_builder_->Disconnect(output_capture_pin_); |
419 graph_builder_->Disconnect(input_sink_pin_); | 454 graph_builder_->Disconnect(input_sink_pin_); |
420 | 455 |
421 // If the _mjpg filter exist disconnect it even if it has not been used. | 456 // If the _mjpg filter exist disconnect it even if it has not been used. |
422 if (mjpg_filter_) { | 457 if (mjpg_filter_) { |
423 graph_builder_->Disconnect(input_mjpg_pin_); | 458 graph_builder_->Disconnect(input_mjpg_pin_); |
424 graph_builder_->Disconnect(output_mjpg_pin_); | 459 graph_builder_->Disconnect(output_mjpg_pin_); |
425 } | 460 } |
461 if (crossbar_filter_) { | |
462 graph_builder_->Disconnect(analog_video_input_pin_); | |
463 graph_builder_->Disconnect(crossbar_video_output_pin_); | |
464 } | |
426 | 465 |
427 if (FAILED(hr)) { | 466 if (FAILED(hr)) { |
428 SetErrorState("Failed to Stop the Capture device"); | 467 SetErrorState("Failed to Stop the Capture device"); |
429 return; | 468 return; |
430 } | 469 } |
431 client_.reset(); | 470 client_.reset(); |
432 state_ = kIdle; | 471 state_ = kIdle; |
433 } | 472 } |
434 | 473 |
435 // Implements SinkFilterObserver::SinkFilterObserver. | 474 // Implements SinkFilterObserver::SinkFilterObserver. |
436 void VideoCaptureDeviceWin::FrameReceived(const uint8* buffer, | 475 void VideoCaptureDeviceWin::FrameReceived(const uint8* buffer, |
437 int length) { | 476 int length) { |
438 client_->OnIncomingCapturedData( | 477 client_->OnIncomingCapturedData( |
439 buffer, length, capture_format_, 0, base::TimeTicks::Now()); | 478 buffer, length, capture_format_, 0, base::TimeTicks::Now()); |
440 } | 479 } |
441 | 480 |
442 bool VideoCaptureDeviceWin::CreateCapabilityMap() { | 481 bool VideoCaptureDeviceWin::CreateCapabilityMap() { |
443 DCHECK(CalledOnValidThread()); | 482 DCHECK(CalledOnValidThread()); |
444 ScopedComPtr<IAMStreamConfig> stream_config; | 483 ScopedComPtr<IAMStreamConfig> stream_config; |
445 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); | 484 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); |
446 if (FAILED(hr)) { | 485 if (FAILED(hr)) { |
447 DPLOG(ERROR) << "Failed to get IAMStreamConfig interface from " | 486 DVLOG(2) << "Failed to get IAMStreamConfig interface from " |
448 "capture device: " << logging::SystemErrorCodeToString(hr); | 487 "capture device"; |
449 return false; | 488 return false; |
450 } | 489 } |
451 | 490 |
452 // Get interface used for getting the frame rate. | 491 // Get interface used for getting the frame rate. |
453 ScopedComPtr<IAMVideoControl> video_control; | 492 ScopedComPtr<IAMVideoControl> video_control; |
454 hr = capture_filter_.QueryInterface(video_control.Receive()); | 493 hr = capture_filter_.QueryInterface(video_control.Receive()); |
455 DLOG_IF(WARNING, FAILED(hr)) << "IAMVideoControl Interface NOT SUPPORTED: " | 494 DVLOG_IF(2, FAILED(hr)) << "IAMVideoControl Interface NOT SUPPORTED"; |
456 << logging::SystemErrorCodeToString(hr); | |
457 | 495 |
458 int count = 0, size = 0; | 496 int count = 0, size = 0; |
459 hr = stream_config->GetNumberOfCapabilities(&count, &size); | 497 hr = stream_config->GetNumberOfCapabilities(&count, &size); |
460 if (FAILED(hr)) { | 498 if (FAILED(hr)) { |
461 DLOG(ERROR) << "Failed to GetNumberOfCapabilities: " | 499 DVLOG(2) << "Failed to GetNumberOfCapabilities"; |
462 << logging::SystemErrorCodeToString(hr); | |
463 return false; | 500 return false; |
464 } | 501 } |
465 | 502 |
466 scoped_ptr<BYTE[]> caps(new BYTE[size]); | 503 scoped_ptr<BYTE[]> caps(new BYTE[size]); |
467 for (int i = 0; i < count; ++i) { | 504 for (int i = 0; i < count; ++i) { |
468 ScopedMediaType media_type; | 505 ScopedMediaType media_type; |
469 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); | 506 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); |
470 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | 507 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() |
471 // macros here since they'll trigger incorrectly. | 508 // macros here since they'll trigger incorrectly. |
472 if (hr != S_OK) { | 509 if (hr != S_OK) { |
473 DLOG(ERROR) << "Failed to GetStreamCaps: " | 510 DVLOG(2) << "Failed to GetStreamCaps"; |
474 << logging::SystemErrorCodeToString(hr); | |
475 return false; | 511 return false; |
476 } | 512 } |
477 | 513 |
478 if (media_type->majortype == MEDIATYPE_Video && | 514 if (media_type->majortype == MEDIATYPE_Video && |
479 media_type->formattype == FORMAT_VideoInfo) { | 515 media_type->formattype == FORMAT_VideoInfo) { |
480 VideoCaptureCapabilityWin capability(i); | 516 VideoCaptureCapabilityWin capability(i); |
481 capability.supported_format.pixel_format = | 517 capability.supported_format.pixel_format = |
482 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | 518 TranslateMediaSubtypeToPixelFormat(media_type->subtype); |
483 if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) | 519 if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
484 continue; | 520 continue; |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
546 (type_support & KSPROPERTY_SUPPORT_SET)) { | 582 (type_support & KSPROPERTY_SUPPORT_SET)) { |
547 KSPROPERTY_VIDEOPROCAMP_S data = {}; | 583 KSPROPERTY_VIDEOPROCAMP_S data = {}; |
548 data.Property.Set = PROPSETID_VIDCAP_VIDEOPROCAMP; | 584 data.Property.Set = PROPSETID_VIDCAP_VIDEOPROCAMP; |
549 data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY; | 585 data.Property.Id = KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY; |
550 data.Property.Flags = KSPROPERTY_TYPE_SET; | 586 data.Property.Flags = KSPROPERTY_TYPE_SET; |
551 data.Value = (power_line_frequency == kPowerLine50Hz) ? 1 : 2; | 587 data.Value = (power_line_frequency == kPowerLine50Hz) ? 1 : 2; |
552 data.Flags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL; | 588 data.Flags = KSPROPERTY_VIDEOPROCAMP_FLAGS_MANUAL; |
553 hr = ks_propset->Set(PROPSETID_VIDCAP_VIDEOPROCAMP, | 589 hr = ks_propset->Set(PROPSETID_VIDCAP_VIDEOPROCAMP, |
554 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, | 590 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, |
555 &data, sizeof(data), &data, sizeof(data)); | 591 &data, sizeof(data), &data, sizeof(data)); |
556 DLOG_IF(ERROR, FAILED(hr)) << "Anti-flicker setting failed: " | 592 DVLOG_IF(ERROR, FAILED(hr)) << "Anti-flicker setting failed."; |
perkj_chrome
2014/09/08 13:32:11
Why are you changing the log macros?
mcasas
2014/09/09 08:22:27
Not intentional, reverted.
| |
557 << logging::SystemErrorCodeToString(hr); | |
558 DVLOG_IF(2, SUCCEEDED(hr)) << "Anti-flicker set correctly."; | 593 DVLOG_IF(2, SUCCEEDED(hr)) << "Anti-flicker set correctly."; |
559 } else { | 594 } else { |
560 DVLOG(2) << "Anti-flicker setting not supported."; | 595 DVLOG(2) << "Anti-flicker setting not supported."; |
561 } | 596 } |
562 } | 597 } |
563 | 598 |
599 // Instantiate a WDM Crossbar Filter and the associated WDM Capture Filter, | |
600 // extract the correct pins from each. The necessary pins are device specific | |
perkj_chrome
2014/09/08 13:32:11
Can you document the pins you are looking for?
mcasas
2014/09/09 08:22:26
Done.
| |
601 // and usually the first Crossbar output pin and the first Capture input pin. | |
602 HRESULT VideoCaptureDeviceWin::InstantiateWDMFiltersAndPins() { | |
603 ScopedComPtr<IMoniker> crossbar_moniker = FindDeviceAndReturnMoniker( | |
604 device_name_.id(), AM_KSCATEGORY_CROSSBAR, L"DevicePath", false); | |
perkj_chrome
2014/09/09 07:54:43
shouldnt this be an exact id comparison of the Dev
mcasas
2014/09/09 08:22:26
Done.
| |
605 if (!crossbar_moniker) | |
606 return E_FAIL; | |
607 | |
608 HRESULT hr = crossbar_moniker->BindToObject(0, 0, IID_IBaseFilter, | |
609 crossbar_filter_.ReceiveVoid()); | |
610 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to bind crossbar filter"; | |
611 if (FAILED(hr) || !crossbar_filter_) | |
612 return E_FAIL; | |
613 | |
614 // Find Crossbar Video Output Pin: This is usually the first output pin. | |
615 crossbar_video_output_pin_ = GetPin( | |
616 crossbar_filter_, PINDIR_OUTPUT, GUID_NULL); | |
617 DLOG_IF(ERROR, !crossbar_video_output_pin_) | |
618 << "Failed to find Crossbar Video Output pin"; | |
619 if (!crossbar_video_output_pin_) | |
620 return E_FAIL; | |
621 | |
622 // Find the WDM capture filter associated to the WDM Crossbar filter. This | |
623 // is a fuzzy matching: they have similar names to the naked eye. Empirically, | |
624 // use the words of the Crossbar Filter name one by one; they are usually | |
625 // Vendor, Chip model etc to search in the WDM Filters list. | |
626 base::StringTokenizer t(device_name_.name(), " "); | |
627 ScopedComPtr<IMoniker> wdm_source_moniker; | |
628 while (!wdm_source_moniker && t.GetNext()) { | |
perkj_chrome
2014/09/09 07:54:43
Does this mean that you first just look for the ve
mcasas
2014/09/09 08:22:26
This is a fuzzy matching so it isn't perfect. We d
perkj_chrome
2014/09/09 10:51:08
For your example- wouldn't "WDM Card Crossbar" mak
mcasas
2014/09/10 13:42:58
OK after some offline discussion, we have decided
| |
629 wdm_source_moniker = FindDeviceAndReturnMoniker( | |
630 t.token(), AM_KSCATEGORY_CAPTURE, L"FriendlyName", false); | |
631 } | |
632 DLOG_IF(ERROR, wdm_source_moniker) << "Couldn't find WDM device named"; | |
633 if (!wdm_source_moniker) | |
634 return E_FAIL; | |
635 | |
636 hr = wdm_source_moniker->BindToObject(0, 0, IID_IBaseFilter, | |
637 capture_filter_.ReceiveVoid()); | |
638 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to bind WDM filter"; | |
639 if (FAILED(hr) || !capture_filter_) | |
640 return E_FAIL; | |
641 | |
642 // Find the WDM Capture Filter's Analog Video input Pin: usually the first | |
643 // input pin. | |
644 analog_video_input_pin_ = GetPin(capture_filter_, PINDIR_INPUT, GUID_NULL); | |
645 DLOG_IF(ERROR, !analog_video_input_pin_) << "Failed to find WDM Video Input"; | |
646 if (!analog_video_input_pin_) | |
647 return E_FAIL; | |
648 return S_OK; | |
649 } | |
650 | |
651 // Add the WDM Crossbar filter to the Graph and connect the pins previously | |
652 // found. | |
653 HRESULT VideoCaptureDeviceWin::AddWDMCrossbarFilterToGraphAndConnect() { | |
654 HRESULT hr = graph_builder_->AddFilter(crossbar_filter_, NULL); | |
655 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to add Crossbar filter to the graph"; | |
656 if (FAILED(hr)) | |
657 return E_FAIL; | |
658 | |
659 hr = graph_builder_->ConnectDirect( | |
660 crossbar_video_output_pin_, analog_video_input_pin_, NULL); | |
661 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to plug WDM filters to each other"; | |
662 if (FAILED(hr)) | |
663 return E_FAIL; | |
664 return S_OK; | |
665 } | |
666 | |
564 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 667 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
565 DCHECK(CalledOnValidThread()); | 668 DCHECK(CalledOnValidThread()); |
669 DVLOG(1) << reason; | |
566 state_ = kError; | 670 state_ = kError; |
567 client_->OnError(reason); | 671 client_->OnError(reason); |
568 } | 672 } |
569 } // namespace media | 673 } // namespace media |
OLD | NEW |