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

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

Issue 546803002: Win Video Capture: add support for WDM capture devices using a WDM Crossbar filter. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Simplified CL to only USB capture devices. 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
« no previous file with comments | « media/video/capture/win/video_capture_device_win.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 (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/sys_string_conversions.h" 13 #include "base/strings/sys_string_conversions.h"
14 #include "base/win/scoped_co_mem.h" 14 #include "base/win/scoped_co_mem.h"
15 #include "base/win/scoped_variant.h" 15 #include "base/win/scoped_variant.h"
16 #include "media/video/capture/win/video_capture_device_mf_win.h" 16 #include "media/video/capture/win/video_capture_device_mf_win.h"
17 17
18 using base::win::ScopedCoMem; 18 using base::win::ScopedCoMem;
19 using base::win::ScopedComPtr; 19 using base::win::ScopedComPtr;
20 using base::win::ScopedVariant; 20 using base::win::ScopedVariant;
21 21
22 namespace media { 22 namespace media {
23 23
24 // Finds and creates a DirectShow Video Capture filter matching the device_name. 24 // Check if a Pin matches a category.
25 // static
perkj_chrome 2014/09/10 14:58:26 nit. Remove static
mcasas 2014/09/10 15:52:45 Done.
26 bool PinMatchesCategory(IPin* pin, REFGUID category) {
27 DCHECK(pin);
28 bool found = false;
29 ScopedComPtr<IKsPropertySet> ks_property;
30 HRESULT hr = ks_property.QueryFrom(pin);
31 if (SUCCEEDED(hr)) {
32 GUID pin_category;
33 DWORD return_value;
34 hr = ks_property->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
35 &pin_category, sizeof(pin_category), &return_value);
36 if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) {
37 found = (pin_category == category);
38 }
39 }
40 return found;
41 }
42
43 // Check if a Pin's MediaType matches a given |major_type|.
44 // static
perkj_chrome 2014/09/10 14:58:26 dito
mcasas 2014/09/10 15:52:45 Done.
45 bool PinMatchesMajorType(IPin* pin, REFGUID major_type) {
46 DCHECK(pin);
47 AM_MEDIA_TYPE connection_media_type;
48 HRESULT hr = pin->ConnectionMediaType(&connection_media_type);
49 if (SUCCEEDED(hr))
50 return connection_media_type.majortype == major_type;
perkj_chrome 2014/09/10 14:58:26 suggest return SUCCEEDED(hr) && connection_media_t
mcasas 2014/09/10 15:52:45 Done.
51 DVLOG(1) << "The pin does not coincide with the type";
52 return false;
53 }
54
55 // Finds and creates a DirectShow Video Capture filter matching the |device_id|.
56 // |class_id| is usually CLSID_VideoInputDeviceCategory for standard DirectShow
57 // devices but might also be AM_KSCATEGORY_CAPTURE or AM_KSCATEGORY_CROSSBAR, to
58 // enumerate WDM capture devices or WDM crossbars, respectively.
25 // static 59 // static
26 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id, 60 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,
61 const CLSID device_class_id,
27 IBaseFilter** filter) { 62 IBaseFilter** filter) {
28 DCHECK(filter); 63 DCHECK(filter);
29 64
30 ScopedComPtr<ICreateDevEnum> dev_enum; 65 ScopedComPtr<ICreateDevEnum> dev_enum;
31 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, 66 HRESULT hr = dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL,
32 CLSCTX_INPROC); 67 CLSCTX_INPROC);
33 if (FAILED(hr)) 68 if (FAILED(hr))
34 return hr; 69 return hr;
35 70
36 ScopedComPtr<IEnumMoniker> enum_moniker; 71 ScopedComPtr<IEnumMoniker> enum_moniker;
37 hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, 72 hr = dev_enum->CreateClassEnumerator(device_class_id, enum_moniker.Receive(),
38 enum_moniker.Receive(), 0); 73 0);
39 // CreateClassEnumerator returns S_FALSE on some Windows OS 74 // CreateClassEnumerator returns S_FALSE on some Windows OS
40 // when no camera exist. Therefore the FAILED macro can't be used. 75 // when no camera exist. Therefore the FAILED macro can't be used.
41 if (hr != S_OK) 76 if (hr != S_OK)
42 return NULL; 77 return NULL;
43 78
44 ScopedComPtr<IMoniker> moniker; 79 ScopedComPtr<IMoniker> moniker;
45 ScopedComPtr<IBaseFilter> capture_filter; 80 ScopedComPtr<IBaseFilter> capture_filter;
46 DWORD fetched = 0; 81 DWORD fetched = 0;
47 while (enum_moniker->Next(1, moniker.Receive(), &fetched) == S_OK) { 82 while (enum_moniker->Next(1, moniker.Receive(), &fetched) == S_OK) {
48 ScopedComPtr<IPropertyBag> prop_bag; 83 ScopedComPtr<IPropertyBag> prop_bag;
(...skipping 27 matching lines...) Expand all
76 moniker.Release(); 111 moniker.Release();
77 } 112 }
78 113
79 *filter = capture_filter.Detach(); 114 *filter = capture_filter.Detach();
80 if (!*filter && SUCCEEDED(hr)) 115 if (!*filter && SUCCEEDED(hr))
81 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); 116 hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
82 117
83 return hr; 118 return hr;
84 } 119 }
85 120
86 // Check if a Pin matches a category. 121 // Finds an IPin on an IBaseFilter given the direction, Category and/or Major
87 // static 122 // Type. If either |category| or |major_type| are GUID_NULL, they are ignored.
88 bool VideoCaptureDeviceWin::PinMatchesCategory(IPin* pin, REFGUID category) {
89 DCHECK(pin);
90 bool found = false;
91 ScopedComPtr<IKsPropertySet> ks_property;
92 HRESULT hr = ks_property.QueryFrom(pin);
93 if (SUCCEEDED(hr)) {
94 GUID pin_category;
95 DWORD return_value;
96 hr = ks_property->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
97 &pin_category, sizeof(pin_category), &return_value);
98 if (SUCCEEDED(hr) && (return_value == sizeof(pin_category))) {
99 found = (pin_category == category);
100 }
101 }
102 return found;
103 }
104
105 // Finds an IPin on an IBaseFilter given the direction and category.
106 // static 123 // static
107 ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter, 124 ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter,
108 PIN_DIRECTION pin_dir, 125 PIN_DIRECTION pin_dir,
109 REFGUID category) { 126 REFGUID category,
127 REFGUID major_type) {
110 ScopedComPtr<IPin> pin; 128 ScopedComPtr<IPin> pin;
111 ScopedComPtr<IEnumPins> pin_enum; 129 ScopedComPtr<IEnumPins> pin_enum;
112 HRESULT hr = filter->EnumPins(pin_enum.Receive()); 130 HRESULT hr = filter->EnumPins(pin_enum.Receive());
113 if (pin_enum == NULL) 131 if (pin_enum == NULL)
114 return pin; 132 return pin;
115 133
116 // Get first unconnected pin. 134 // Get first unconnected pin.
117 hr = pin_enum->Reset(); // set to first pin 135 hr = pin_enum->Reset(); // set to first pin
118 while ((hr = pin_enum->Next(1, pin.Receive(), NULL)) == S_OK) { 136 while ((hr = pin_enum->Next(1, pin.Receive(), NULL)) == S_OK) {
119 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1); 137 PIN_DIRECTION this_pin_dir = static_cast<PIN_DIRECTION>(-1);
120 hr = pin->QueryDirection(&this_pin_dir); 138 hr = pin->QueryDirection(&this_pin_dir);
121 if (pin_dir == this_pin_dir) { 139 if (pin_dir == this_pin_dir) {
122 if (category == GUID_NULL || PinMatchesCategory(pin, category)) 140 if ((category == GUID_NULL || PinMatchesCategory(pin, category)) &&
141 (major_type == GUID_NULL || PinMatchesMajorType(pin, major_type))) {
123 return pin; 142 return pin;
143 }
124 } 144 }
125 pin.Release(); 145 pin.Release();
126 } 146 }
127 147
128 DCHECK(!pin); 148 DCHECK(!pin);
129 return pin; 149 return pin;
130 } 150 }
131 151
132 // static 152 // static
133 VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat( 153 VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
211 if (sink_filter_) { 231 if (sink_filter_) {
212 graph_builder_->RemoveFilter(sink_filter_); 232 graph_builder_->RemoveFilter(sink_filter_);
213 sink_filter_ = NULL; 233 sink_filter_ = NULL;
214 } 234 }
215 235
216 if (capture_filter_) 236 if (capture_filter_)
217 graph_builder_->RemoveFilter(capture_filter_); 237 graph_builder_->RemoveFilter(capture_filter_);
218 238
219 if (mjpg_filter_) 239 if (mjpg_filter_)
220 graph_builder_->RemoveFilter(mjpg_filter_); 240 graph_builder_->RemoveFilter(mjpg_filter_);
241
242 if (crossbar_filter_)
243 graph_builder_->RemoveFilter(crossbar_filter_);
221 } 244 }
222 } 245 }
223 246
224 bool VideoCaptureDeviceWin::Init() { 247 bool VideoCaptureDeviceWin::Init() {
225 DCHECK(CalledOnValidThread()); 248 DCHECK(CalledOnValidThread());
226 HRESULT hr = GetDeviceFilter(device_name_.id(), capture_filter_.Receive()); 249 HRESULT hr;
250
251 if (device_name_.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR) {
252 hr = InstantiateWDMFiltersAndPins();
253 } else {
254 hr = GetDeviceFilter(device_name_.id(), CLSID_VideoInputDeviceCategory,
255 capture_filter_.Receive());
256 }
227 if (!capture_filter_) { 257 if (!capture_filter_) {
228 DLOG(ERROR) << "Failed to create capture filter: " 258 DLOG(ERROR) << "Failed to create capture filter: "
229 << logging::SystemErrorCodeToString(hr); 259 << logging::SystemErrorCodeToString(hr);
230 return false; 260 return false;
231 } 261 }
232 262
233 output_capture_pin_ = 263 output_capture_pin_ =
234 GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE); 264 GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, GUID_NULL);
235 if (!output_capture_pin_) { 265 if (!output_capture_pin_) {
236 DLOG(ERROR) << "Failed to get capture output pin"; 266 DLOG(ERROR) << "Failed to get capture output pin";
237 return false; 267 return false;
238 } 268 }
239 269
240 // Create the sink filter used for receiving Captured frames. 270 // Create the sink filter used for receiving Captured frames.
241 sink_filter_ = new SinkFilter(this); 271 sink_filter_ = new SinkFilter(this);
242 if (sink_filter_ == NULL) { 272 if (sink_filter_ == NULL) {
243 DLOG(ERROR) << "Failed to create send filter"; 273 DLOG(ERROR) << "Failed to create send filter";
244 return false; 274 return false;
(...skipping 16 matching lines...) Expand all
261 return false; 291 return false;
262 } 292 }
263 293
264 hr = graph_builder_->AddFilter(capture_filter_, NULL); 294 hr = graph_builder_->AddFilter(capture_filter_, NULL);
265 if (FAILED(hr)) { 295 if (FAILED(hr)) {
266 DLOG(ERROR) << "Failed to add the capture device to the graph: " 296 DLOG(ERROR) << "Failed to add the capture device to the graph: "
267 << logging::SystemErrorCodeToString(hr); 297 << logging::SystemErrorCodeToString(hr);
268 return false; 298 return false;
269 } 299 }
270 300
301 if (device_name_.capture_api_type() == Name::DIRECT_SHOW_WDM_CROSSBAR &&
302 FAILED(AddWDMCrossbarFilterToGraphAndConnect())) {
303 DLOG(ERROR) << "Failed to add the WDM Crossbar filter to the graph.";
304 return false;
305 }
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 DLOG(ERROR) << "Failed to add the send filter to the graph: "
274 << logging::SystemErrorCodeToString(hr); 310 << logging::SystemErrorCodeToString(hr);
275 return false; 311 return false;
276 } 312 }
277 313
278 return CreateCapabilityMap(); 314 return CreateCapabilityMap();
279 } 315 }
280 316
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 SetErrorState("Failed to set capture device output format"); 377 SetErrorState("Failed to set capture device output format");
342 return; 378 return;
343 } 379 }
344 } 380 }
345 381
346 if (format.pixel_format == PIXEL_FORMAT_MJPEG && !mjpg_filter_.get()) { 382 if (format.pixel_format == PIXEL_FORMAT_MJPEG && !mjpg_filter_.get()) {
347 // Create MJPG filter if we need it. 383 // Create MJPG filter if we need it.
348 hr = mjpg_filter_.CreateInstance(CLSID_MjpegDec, NULL, CLSCTX_INPROC); 384 hr = mjpg_filter_.CreateInstance(CLSID_MjpegDec, NULL, CLSCTX_INPROC);
349 385
350 if (SUCCEEDED(hr)) { 386 if (SUCCEEDED(hr)) {
351 input_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_INPUT, GUID_NULL); 387 input_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_INPUT, GUID_NULL,
352 output_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_OUTPUT, GUID_NULL); 388 GUID_NULL);
389 output_mjpg_pin_ = GetPin(mjpg_filter_, PINDIR_OUTPUT, GUID_NULL,
390 GUID_NULL);
353 hr = graph_builder_->AddFilter(mjpg_filter_, NULL); 391 hr = graph_builder_->AddFilter(mjpg_filter_, NULL);
354 } 392 }
355 393
356 if (FAILED(hr)) { 394 if (FAILED(hr)) {
357 mjpg_filter_.Release(); 395 mjpg_filter_.Release();
358 input_mjpg_pin_.Release(); 396 input_mjpg_pin_.Release();
359 output_mjpg_pin_.Release(); 397 output_mjpg_pin_.Release();
360 } 398 }
361 } 399 }
362 400
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
416 } 454 }
417 455
418 graph_builder_->Disconnect(output_capture_pin_); 456 graph_builder_->Disconnect(output_capture_pin_);
419 graph_builder_->Disconnect(input_sink_pin_); 457 graph_builder_->Disconnect(input_sink_pin_);
420 458
421 // If the _mjpg filter exist disconnect it even if it has not been used. 459 // If the _mjpg filter exist disconnect it even if it has not been used.
422 if (mjpg_filter_) { 460 if (mjpg_filter_) {
423 graph_builder_->Disconnect(input_mjpg_pin_); 461 graph_builder_->Disconnect(input_mjpg_pin_);
424 graph_builder_->Disconnect(output_mjpg_pin_); 462 graph_builder_->Disconnect(output_mjpg_pin_);
425 } 463 }
464 if (crossbar_filter_) {
465 graph_builder_->Disconnect(analog_video_input_pin_);
466 graph_builder_->Disconnect(crossbar_video_output_pin_);
467 }
426 468
427 if (FAILED(hr)) { 469 if (FAILED(hr)) {
428 SetErrorState("Failed to Stop the Capture device"); 470 SetErrorState("Failed to Stop the Capture device");
429 return; 471 return;
430 } 472 }
431 client_.reset(); 473 client_.reset();
432 state_ = kIdle; 474 state_ = kIdle;
433 } 475 }
434 476
435 // Implements SinkFilterObserver::SinkFilterObserver. 477 // Implements SinkFilterObserver::SinkFilterObserver.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY, 596 KSPROPERTY_VIDEOPROCAMP_POWERLINE_FREQUENCY,
555 &data, sizeof(data), &data, sizeof(data)); 597 &data, sizeof(data), &data, sizeof(data));
556 DLOG_IF(ERROR, FAILED(hr)) << "Anti-flicker setting failed: " 598 DLOG_IF(ERROR, FAILED(hr)) << "Anti-flicker setting failed: "
557 << logging::SystemErrorCodeToString(hr); 599 << logging::SystemErrorCodeToString(hr);
558 DVLOG_IF(2, SUCCEEDED(hr)) << "Anti-flicker set correctly."; 600 DVLOG_IF(2, SUCCEEDED(hr)) << "Anti-flicker set correctly.";
559 } else { 601 } else {
560 DVLOG(2) << "Anti-flicker setting not supported."; 602 DVLOG(2) << "Anti-flicker setting not supported.";
561 } 603 }
562 } 604 }
563 605
606 // Instantiate a WDM Crossbar Filter and the associated WDM Capture Filter,
607 // extract the correct pins from each. The necessary pins are device specific
608 // and usually the first Crossbar output pin, with a name similar to "Video
609 // Decoder Out" and the first Capture input pin, with a name like "Analog Video
610 // In". These pins have no special Category.
611 HRESULT VideoCaptureDeviceWin::InstantiateWDMFiltersAndPins() {
612 HRESULT hr = VideoCaptureDeviceWin::GetDeviceFilter(
613 device_name_.id(),
614 AM_KSCATEGORY_CROSSBAR,
615 crossbar_filter_.Receive());
616 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to bind WDM Crossbar filter";
617 if (FAILED(hr) || !crossbar_filter_)
618 return E_FAIL;
619
620 // Find Crossbar Video Output Pin: This is usually the first output pin.
621 crossbar_video_output_pin_ = GetPin(crossbar_filter_, PINDIR_OUTPUT,
622 GUID_NULL, MEDIATYPE_AnalogVideo);
623 DLOG_IF(ERROR, !crossbar_video_output_pin_)
624 << "Failed to find Crossbar Video Output pin";
625 if (!crossbar_video_output_pin_)
626 return E_FAIL;
627
628 // Use the WDM capture filter associated to the WDM Crossbar filter.
629 hr = VideoCaptureDeviceWin::GetDeviceFilter(device_name_.capabilities_id(),
630 AM_KSCATEGORY_CAPTURE,
631 capture_filter_.Receive());
632 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to bind WDM Capture filter";
633 if (FAILED(hr) || !capture_filter_)
634 return E_FAIL;
635
636 // Find the WDM Capture Filter's Analog Video input Pin: usually the first
637 // input pin.
638 analog_video_input_pin_ = GetPin(capture_filter_, PINDIR_INPUT, GUID_NULL,
639 MEDIATYPE_AnalogVideo);
640 DLOG_IF(ERROR, !analog_video_input_pin_) << "Failed to find WDM Video Input";
641 if (!analog_video_input_pin_)
642 return E_FAIL;
643 return S_OK;
644 }
645
646 // Add the WDM Crossbar filter to the Graph and connect the pins previously
647 // found.
648 HRESULT VideoCaptureDeviceWin::AddWDMCrossbarFilterToGraphAndConnect() {
649 HRESULT hr = graph_builder_->AddFilter(crossbar_filter_, NULL);
650 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to add Crossbar filter to the graph";
651 if (FAILED(hr))
652 return E_FAIL;
653
654 hr = graph_builder_->ConnectDirect(
655 crossbar_video_output_pin_, analog_video_input_pin_, NULL);
656 DPLOG_IF(ERROR, FAILED(hr)) << "Failed to plug WDM filters to each other";
657 if (FAILED(hr))
658 return E_FAIL;
659 return S_OK;
660 }
661
564 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { 662 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) {
565 DCHECK(CalledOnValidThread()); 663 DCHECK(CalledOnValidThread());
566 state_ = kError; 664 state_ = kError;
567 client_->OnError(reason); 665 client_->OnError(reason);
568 } 666 }
569 } // namespace media 667 } // namespace media
OLDNEW
« no previous file with comments | « media/video/capture/win/video_capture_device_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698