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> |
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 if (capture_filter_) | 216 if (capture_filter_) |
217 graph_builder_->RemoveFilter(capture_filter_); | 217 graph_builder_->RemoveFilter(capture_filter_); |
218 | 218 |
219 if (mjpg_filter_) | 219 if (mjpg_filter_) |
220 graph_builder_->RemoveFilter(mjpg_filter_); | 220 graph_builder_->RemoveFilter(mjpg_filter_); |
221 } | 221 } |
222 } | 222 } |
223 | 223 |
224 bool VideoCaptureDeviceWin::Init() { | 224 bool VideoCaptureDeviceWin::Init() { |
225 DCHECK(CalledOnValidThread()); | 225 DCHECK(CalledOnValidThread()); |
226 HRESULT hr = GetDeviceFilter(device_name_.id(), capture_filter_.Receive()); | 226 |
227 if (!capture_filter_) { | 227 if (!VideoCaptureDeviceWin::GetDeviceSupportedFormats(device_name_, |
228 DLOG(ERROR) << "Failed to create capture filter: " | 228 &capture_filter_, |
229 << logging::SystemErrorCodeToString(hr); | 229 &output_capture_pin_, |
230 &capabilities_)) { | |
230 return false; | 231 return false; |
231 } | 232 } |
232 | 233 |
233 output_capture_pin_ = | |
234 GetPin(capture_filter_, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE); | |
235 if (!output_capture_pin_) { | |
236 DLOG(ERROR) << "Failed to get capture output pin"; | |
237 return false; | |
238 } | |
239 | |
240 // Create the sink filter used for receiving Captured frames. | 234 // Create the sink filter used for receiving Captured frames. |
241 sink_filter_ = new SinkFilter(this); | 235 sink_filter_ = new SinkFilter(this); |
242 if (sink_filter_ == NULL) { | 236 if (sink_filter_ == NULL) { |
243 DLOG(ERROR) << "Failed to create send filter"; | 237 DLOG(ERROR) << "Failed to create send filter"; |
244 return false; | 238 return false; |
245 } | 239 } |
246 | 240 |
247 input_sink_pin_ = sink_filter_->GetPin(0); | 241 input_sink_pin_ = sink_filter_->GetPin(0); |
248 | 242 |
249 hr = graph_builder_.CreateInstance(CLSID_FilterGraph, NULL, | 243 HRESULT hr = graph_builder_.CreateInstance( |
250 CLSCTX_INPROC_SERVER); | 244 CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER); |
251 if (FAILED(hr)) { | 245 if (FAILED(hr)) { |
252 DLOG(ERROR) << "Failed to create graph builder: " | 246 DLOG(ERROR) << "Failed to create graph builder: " |
253 << logging::SystemErrorCodeToString(hr); | 247 << logging::SystemErrorCodeToString(hr); |
254 return false; | 248 return false; |
255 } | 249 } |
256 | 250 |
257 hr = graph_builder_.QueryInterface(media_control_.Receive()); | 251 hr = graph_builder_.QueryInterface(media_control_.Receive()); |
258 if (FAILED(hr)) { | 252 if (FAILED(hr)) { |
259 DLOG(ERROR) << "Failed to create media control builder: " | 253 DLOG(ERROR) << "Failed to create media control builder: " |
260 << logging::SystemErrorCodeToString(hr); | 254 << logging::SystemErrorCodeToString(hr); |
261 return false; | 255 return false; |
262 } | 256 } |
263 | 257 |
264 hr = graph_builder_->AddFilter(capture_filter_, NULL); | 258 hr = graph_builder_->AddFilter(capture_filter_, NULL); |
265 if (FAILED(hr)) { | 259 if (FAILED(hr)) { |
266 DLOG(ERROR) << "Failed to add the capture device to the graph: " | 260 DLOG(ERROR) << "Failed to add the capture device to the graph: " |
267 << logging::SystemErrorCodeToString(hr); | 261 << logging::SystemErrorCodeToString(hr); |
268 return false; | 262 return false; |
269 } | 263 } |
270 | 264 |
271 hr = graph_builder_->AddFilter(sink_filter_, NULL); | 265 hr = graph_builder_->AddFilter(sink_filter_, NULL); |
272 if (FAILED(hr)) { | 266 if (FAILED(hr)) { |
273 DLOG(ERROR) << "Failed to add the send filter to the graph: " | 267 DLOG(ERROR) << "Failed to add the send filter to the graph: " |
274 << logging::SystemErrorCodeToString(hr); | 268 << logging::SystemErrorCodeToString(hr); |
275 return false; | 269 return false; |
276 } | 270 } |
277 | 271 |
278 return CreateCapabilityMap(); | 272 return true; |
279 } | 273 } |
280 | 274 |
281 void VideoCaptureDeviceWin::AllocateAndStart( | 275 void VideoCaptureDeviceWin::AllocateAndStart( |
282 const VideoCaptureParams& params, | 276 const VideoCaptureParams& params, |
283 scoped_ptr<VideoCaptureDevice::Client> client) { | 277 scoped_ptr<VideoCaptureDevice::Client> client) { |
284 DCHECK(CalledOnValidThread()); | 278 DCHECK(CalledOnValidThread()); |
285 if (state_ != kIdle) | 279 if (state_ != kIdle) |
286 return; | 280 return; |
287 | 281 |
288 client_ = client.Pass(); | 282 client_ = client.Pass(); |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
432 state_ = kIdle; | 426 state_ = kIdle; |
433 } | 427 } |
434 | 428 |
435 // Implements SinkFilterObserver::SinkFilterObserver. | 429 // Implements SinkFilterObserver::SinkFilterObserver. |
436 void VideoCaptureDeviceWin::FrameReceived(const uint8* buffer, | 430 void VideoCaptureDeviceWin::FrameReceived(const uint8* buffer, |
437 int length) { | 431 int length) { |
438 client_->OnIncomingCapturedData( | 432 client_->OnIncomingCapturedData( |
439 buffer, length, capture_format_, 0, base::TimeTicks::Now()); | 433 buffer, length, capture_format_, 0, base::TimeTicks::Now()); |
440 } | 434 } |
441 | 435 |
442 bool VideoCaptureDeviceWin::CreateCapabilityMap() { | 436 // static |
443 DCHECK(CalledOnValidThread()); | 437 bool VideoCaptureDeviceWin::GetDeviceSupportedFormats( |
perkj_chrome
2014/09/19 10:04:55
It looks like this is doing much more that gettign
| |
438 const Name& device, | |
439 ScopedComPtr<IBaseFilter>* capture_filter, | |
440 ScopedComPtr<IPin>* output_capture_pin, | |
441 CapabilityList* capabilities) { | |
442 HRESULT hr = GetDeviceFilter(device.id(), capture_filter->Receive()); | |
443 if (!capture_filter) { | |
444 DLOG(ERROR) << "Failed to create capture filter: " | |
445 << logging::SystemErrorCodeToString(hr); | |
446 return false; | |
447 } | |
448 | |
449 *output_capture_pin = | |
450 GetPin(*capture_filter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE); | |
451 if (!*output_capture_pin) { | |
452 DLOG(ERROR) << "Failed to get capture output pin"; | |
453 return false; | |
454 } | |
455 | |
444 ScopedComPtr<IAMStreamConfig> stream_config; | 456 ScopedComPtr<IAMStreamConfig> stream_config; |
445 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); | 457 hr = output_capture_pin->QueryInterface(stream_config.Receive()); |
446 if (FAILED(hr)) { | 458 if (FAILED(hr)) { |
447 DPLOG(ERROR) << "Failed to get IAMStreamConfig interface from " | 459 DPLOG(ERROR) << "Failed to get IAMStreamConfig interface from " |
448 "capture device: " << logging::SystemErrorCodeToString(hr); | 460 "capture device: " << logging::SystemErrorCodeToString(hr); |
449 return false; | 461 return false; |
450 } | 462 } |
451 | 463 |
452 // Get interface used for getting the frame rate. | 464 // Get interface used for getting the frame rate. |
453 ScopedComPtr<IAMVideoControl> video_control; | 465 ScopedComPtr<IAMVideoControl> video_control; |
454 hr = capture_filter_.QueryInterface(video_control.Receive()); | 466 hr = capture_filter->QueryInterface(video_control.Receive()); |
455 DLOG_IF(WARNING, FAILED(hr)) << "IAMVideoControl Interface NOT SUPPORTED: " | 467 DLOG_IF(WARNING, FAILED(hr)) << "IAMVideoControl Interface NOT SUPPORTED: " |
456 << logging::SystemErrorCodeToString(hr); | 468 << logging::SystemErrorCodeToString(hr); |
457 | 469 |
458 int count = 0, size = 0; | 470 int count = 0, size = 0; |
459 hr = stream_config->GetNumberOfCapabilities(&count, &size); | 471 hr = stream_config->GetNumberOfCapabilities(&count, &size); |
460 if (FAILED(hr)) { | 472 if (FAILED(hr)) { |
461 DLOG(ERROR) << "Failed to GetNumberOfCapabilities: " | 473 DLOG(ERROR) << "Failed to GetNumberOfCapabilities: " |
462 << logging::SystemErrorCodeToString(hr); | 474 << logging::SystemErrorCodeToString(hr); |
463 return false; | 475 return false; |
464 } | 476 } |
465 | 477 |
466 scoped_ptr<BYTE[]> caps(new BYTE[size]); | 478 scoped_ptr<BYTE[]> caps(new BYTE[size]); |
467 for (int i = 0; i < count; ++i) { | 479 for (int i = 0; i < count; ++i) { |
468 ScopedMediaType media_type; | 480 ScopedMediaType media_type; |
469 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); | 481 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); |
470 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | 482 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() |
471 // macros here since they'll trigger incorrectly. | 483 // macros here since they'll trigger incorrectly. |
472 if (hr != S_OK) { | 484 if (hr != S_OK) { |
473 DLOG(ERROR) << "Failed to GetStreamCaps: " | 485 DLOG(ERROR) << "Failed to GetStreamCaps: " |
474 << logging::SystemErrorCodeToString(hr); | 486 << logging::SystemErrorCodeToString(hr); |
475 return false; | 487 continue; |
476 } | 488 } |
477 | 489 |
478 if (media_type->majortype == MEDIATYPE_Video && | 490 if (media_type->majortype == MEDIATYPE_Video && |
479 media_type->formattype == FORMAT_VideoInfo) { | 491 media_type->formattype == FORMAT_VideoInfo) { |
480 VideoCaptureCapabilityWin capability(i); | 492 VideoCaptureCapabilityWin capability(i); |
481 capability.supported_format.pixel_format = | 493 capability.supported_format.pixel_format = |
482 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | 494 TranslateMediaSubtypeToPixelFormat(media_type->subtype); |
483 if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) | 495 if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
484 continue; | 496 continue; |
485 | 497 |
486 VIDEOINFOHEADER* h = | 498 VIDEOINFOHEADER* h = |
487 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | 499 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
488 capability.supported_format.frame_size.SetSize(h->bmiHeader.biWidth, | 500 capability.supported_format.frame_size.SetSize(h->bmiHeader.biWidth, |
489 h->bmiHeader.biHeight); | 501 h->bmiHeader.biHeight); |
490 | 502 |
491 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use | 503 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use |
492 // the value from VIDEOINFOHEADER. | 504 // the value from VIDEOINFOHEADER. |
493 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; | 505 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; |
494 if (video_control) { | 506 if (video_control) { |
495 ScopedCoMem<LONGLONG> max_fps; | 507 ScopedCoMem<LONGLONG> max_fps; |
496 LONG list_size = 0; | 508 LONG list_size = 0; |
497 SIZE size = {capability.supported_format.frame_size.width(), | 509 SIZE size = {capability.supported_format.frame_size.width(), |
498 capability.supported_format.frame_size.height()}; | 510 capability.supported_format.frame_size.height()}; |
499 | 511 |
500 // GetFrameRateList doesn't return max frame rate always | 512 // GetFrameRateList doesn't return max frame rate always |
501 // eg: Logitech Notebook. This may be due to a bug in that API | 513 // eg: Logitech Notebook. This may be due to a bug in that API |
502 // because GetFrameRateList array is reversed in the above camera. So | 514 // because GetFrameRateList array is reversed in the above camera. So |
503 // a util method written. Can't assume the first value will return | 515 // a util method written. Can't assume the first value will return |
504 // the max fps. | 516 // the max fps. |
505 hr = video_control->GetFrameRateList(output_capture_pin_, i, size, | 517 hr = video_control->GetFrameRateList(*output_capture_pin, i, size, |
506 &list_size, &max_fps); | 518 &list_size, &max_fps); |
507 // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some | 519 // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some |
508 // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates | 520 // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates |
509 // into success, so explicitly check S_OK. See http://crbug.com/306237. | 521 // into success, so explicitly check S_OK. See http://crbug.com/306237. |
510 if (hr == S_OK && list_size > 0 && max_fps) { | 522 if (hr == S_OK && list_size > 0 && max_fps) { |
511 time_per_frame = *std::min_element(max_fps.get(), | 523 time_per_frame = *std::min_element(max_fps.get(), |
512 max_fps.get() + list_size); | 524 max_fps.get() + list_size); |
513 } | 525 } |
514 } | 526 } |
515 | 527 |
516 capability.supported_format.frame_rate = | 528 capability.supported_format.frame_rate = |
517 (time_per_frame > 0) | 529 (time_per_frame > 0) |
518 ? (kSecondsToReferenceTime / static_cast<float>(time_per_frame)) | 530 ? (kSecondsToReferenceTime / static_cast<float>(time_per_frame)) |
519 : 0.0; | 531 : 0.0; |
520 | 532 |
521 // DirectShow works at the moment only on integer frame_rate but the | 533 capabilities->Add(capability); |
522 // best capability matching class works on rational frame rates. | |
523 capability.frame_rate_numerator = capability.supported_format.frame_rate; | |
524 capability.frame_rate_denominator = 1; | |
525 | |
526 capabilities_.Add(capability); | |
527 } | 534 } |
528 } | 535 } |
529 | 536 |
530 return !capabilities_.empty(); | 537 return !capabilities->empty(); |
531 } | 538 } |
532 | 539 |
533 // Set the power line frequency removal in |capture_filter_| if available. | 540 // Set the power line frequency removal in |capture_filter_| if available. |
534 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter() { | 541 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter() { |
535 const int power_line_frequency = GetPowerLineFrequencyForLocation(); | 542 const int power_line_frequency = GetPowerLineFrequencyForLocation(); |
536 if (power_line_frequency != kPowerLine50Hz && | 543 if (power_line_frequency != kPowerLine50Hz && |
537 power_line_frequency != kPowerLine60Hz) { | 544 power_line_frequency != kPowerLine60Hz) { |
538 return; | 545 return; |
539 } | 546 } |
540 ScopedComPtr<IKsPropertySet> ks_propset; | 547 ScopedComPtr<IKsPropertySet> ks_propset; |
(...skipping 19 matching lines...) Expand all Loading... | |
560 DVLOG(2) << "Anti-flicker setting not supported."; | 567 DVLOG(2) << "Anti-flicker setting not supported."; |
561 } | 568 } |
562 } | 569 } |
563 | 570 |
564 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 571 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
565 DCHECK(CalledOnValidThread()); | 572 DCHECK(CalledOnValidThread()); |
566 state_ = kError; | 573 state_ = kError; |
567 client_->OnError(reason); | 574 client_->OnError(reason); |
568 } | 575 } |
569 } // namespace media | 576 } // namespace media |
OLD | NEW |