Chromium Code Reviews| 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/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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |