| 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 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 280 | 280 |
| 281 void VideoCaptureDeviceWin::AllocateAndStart( | 281 void VideoCaptureDeviceWin::AllocateAndStart( |
| 282 const VideoCaptureParams& params, | 282 const VideoCaptureParams& params, |
| 283 scoped_ptr<VideoCaptureDevice::Client> client) { | 283 scoped_ptr<VideoCaptureDevice::Client> client) { |
| 284 DCHECK(CalledOnValidThread()); | 284 DCHECK(CalledOnValidThread()); |
| 285 if (state_ != kIdle) | 285 if (state_ != kIdle) |
| 286 return; | 286 return; |
| 287 | 287 |
| 288 client_ = client.Pass(); | 288 client_ = client.Pass(); |
| 289 | 289 |
| 290 // Get the camera capability that best match the requested resolution. | 290 // Get the camera capability that best match the requested format. |
| 291 const VideoCaptureCapabilityWin& found_capability = | 291 const VideoCaptureCapabilityWin& found_capability = |
| 292 capabilities_.GetBestMatchedFormat( | 292 *GetBestMatchedFormat(params.requested_format, capabilities_); |
| 293 params.requested_format.frame_size.width(), | 293 VideoCaptureFormat format = found_capability.second; |
| 294 params.requested_format.frame_size.height(), | |
| 295 params.requested_format.frame_rate); | |
| 296 VideoCaptureFormat format = found_capability.supported_format; | |
| 297 | 294 |
| 298 // Reduce the frame rate if the requested frame rate is lower | 295 // Reduce the frame rate if the requested frame rate is lower |
| 299 // than the capability. | 296 // than the capability. |
| 300 if (format.frame_rate > params.requested_format.frame_rate) | 297 format.frame_rate = |
| 301 format.frame_rate = params.requested_format.frame_rate; | 298 std::min(format.frame_rate, params.requested_format.frame_rate); |
| 302 | 299 |
| 303 ScopedComPtr<IAMStreamConfig> stream_config; | 300 ScopedComPtr<IAMStreamConfig> stream_config; |
| 304 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); | 301 HRESULT hr = output_capture_pin_.QueryInterface(stream_config.Receive()); |
| 305 if (FAILED(hr)) { | 302 if (FAILED(hr)) { |
| 306 SetErrorState("Can't get the Capture format settings"); | 303 SetErrorState("Can't get the Capture format settings"); |
| 307 return; | 304 return; |
| 308 } | 305 } |
| 309 | 306 |
| 310 int count = 0, size = 0; | 307 int count = 0, size = 0; |
| 311 hr = stream_config->GetNumberOfCapabilities(&count, &size); | 308 hr = stream_config->GetNumberOfCapabilities(&count, &size); |
| 312 if (FAILED(hr)) { | 309 if (FAILED(hr)) { |
| 313 SetErrorState("Failed to GetNumberOfCapabilities"); | 310 SetErrorState("Failed to GetNumberOfCapabilities"); |
| 314 return; | 311 return; |
| 315 } | 312 } |
| 316 | 313 |
| 317 scoped_ptr<BYTE[]> caps(new BYTE[size]); | 314 scoped_ptr<BYTE[]> caps(new BYTE[size]); |
| 318 ScopedMediaType media_type; | 315 ScopedMediaType media_type; |
| 319 | 316 |
| 320 // Get the windows capability from the capture device. | 317 // Get the windows capability from the capture device. |
| 321 // GetStreamCaps can return S_FALSE which we consider an error. Therefore the | 318 // GetStreamCaps can return S_FALSE which we consider an error. Therefore the |
| 322 // FAILED macro can't be used. | 319 // FAILED macro can't be used. |
| 323 hr = stream_config->GetStreamCaps( | 320 hr = stream_config->GetStreamCaps( |
| 324 found_capability.stream_index, media_type.Receive(), caps.get()); | 321 found_capability.first, media_type.Receive(), caps.get()); |
| 325 if (hr != S_OK) { | 322 if (hr != S_OK) { |
| 326 SetErrorState("Failed to get capture device capabilities"); | 323 SetErrorState("Failed to get capture device capabilities"); |
| 327 return; | 324 return; |
| 328 } else { | 325 } else { |
| 329 if (media_type->formattype == FORMAT_VideoInfo) { | 326 if (media_type->formattype == FORMAT_VideoInfo) { |
| 330 VIDEOINFOHEADER* h = | 327 VIDEOINFOHEADER* h = |
| 331 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | 328 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
| 332 if (format.frame_rate > 0) | 329 if (format.frame_rate > 0) |
| 333 h->AvgTimePerFrame = kSecondsToReferenceTime / format.frame_rate; | 330 h->AvgTimePerFrame = kSecondsToReferenceTime / format.frame_rate; |
| 334 } | 331 } |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 457 | 454 |
| 458 int count = 0, size = 0; | 455 int count = 0, size = 0; |
| 459 hr = stream_config->GetNumberOfCapabilities(&count, &size); | 456 hr = stream_config->GetNumberOfCapabilities(&count, &size); |
| 460 if (FAILED(hr)) { | 457 if (FAILED(hr)) { |
| 461 DLOG(ERROR) << "Failed to GetNumberOfCapabilities: " | 458 DLOG(ERROR) << "Failed to GetNumberOfCapabilities: " |
| 462 << logging::SystemErrorCodeToString(hr); | 459 << logging::SystemErrorCodeToString(hr); |
| 463 return false; | 460 return false; |
| 464 } | 461 } |
| 465 | 462 |
| 466 scoped_ptr<BYTE[]> caps(new BYTE[size]); | 463 scoped_ptr<BYTE[]> caps(new BYTE[size]); |
| 467 for (int i = 0; i < count; ++i) { | 464 for (int stream_index = 0; stream_index < count; ++stream_index) { |
| 468 ScopedMediaType media_type; | 465 ScopedMediaType media_type; |
| 469 hr = stream_config->GetStreamCaps(i, media_type.Receive(), caps.get()); | 466 hr = stream_config->GetStreamCaps( |
| 467 stream_index, media_type.Receive(), caps.get()); |
| 470 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() | 468 // GetStreamCaps() may return S_FALSE, so don't use FAILED() or SUCCEED() |
| 471 // macros here since they'll trigger incorrectly. | 469 // macros here since they'll trigger incorrectly. |
| 472 if (hr != S_OK) { | 470 if (hr != S_OK) { |
| 473 DLOG(ERROR) << "Failed to GetStreamCaps: " | 471 DLOG(ERROR) << "Failed to GetStreamCaps: " |
| 474 << logging::SystemErrorCodeToString(hr); | 472 << logging::SystemErrorCodeToString(hr); |
| 475 return false; | 473 return false; |
| 476 } | 474 } |
| 477 | 475 |
| 478 if (media_type->majortype == MEDIATYPE_Video && | 476 if (media_type->majortype == MEDIATYPE_Video && |
| 479 media_type->formattype == FORMAT_VideoInfo) { | 477 media_type->formattype == FORMAT_VideoInfo) { |
| 480 VideoCaptureCapabilityWin capability(i); | 478 VideoCaptureFormat format; |
| 481 capability.supported_format.pixel_format = | 479 format.pixel_format = |
| 482 TranslateMediaSubtypeToPixelFormat(media_type->subtype); | 480 TranslateMediaSubtypeToPixelFormat(media_type->subtype); |
| 483 if (capability.supported_format.pixel_format == PIXEL_FORMAT_UNKNOWN) | 481 if (format.pixel_format == PIXEL_FORMAT_UNKNOWN) |
| 484 continue; | 482 continue; |
| 485 | 483 |
| 486 VIDEOINFOHEADER* h = | 484 VIDEOINFOHEADER* h = |
| 487 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | 485 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
| 488 capability.supported_format.frame_size.SetSize(h->bmiHeader.biWidth, | 486 format.frame_size.SetSize(h->bmiHeader.biWidth, h->bmiHeader.biHeight); |
| 489 h->bmiHeader.biHeight); | |
| 490 | 487 |
| 491 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use | 488 // Try to get a better |time_per_frame| from IAMVideoControl. If not, use |
| 492 // the value from VIDEOINFOHEADER. | 489 // the value from VIDEOINFOHEADER. |
| 493 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; | 490 REFERENCE_TIME time_per_frame = h->AvgTimePerFrame; |
| 494 if (video_control) { | 491 if (video_control) { |
| 495 ScopedCoMem<LONGLONG> max_fps; | 492 ScopedCoMem<LONGLONG> max_fps; |
| 496 LONG list_size = 0; | 493 LONG list_size = 0; |
| 497 SIZE size = {capability.supported_format.frame_size.width(), | 494 const SIZE size = {format.frame_size.width(), |
| 498 capability.supported_format.frame_size.height()}; | 495 format.frame_size.height()}; |
| 499 | |
| 500 // GetFrameRateList doesn't return max frame rate always | 496 // GetFrameRateList doesn't return max frame rate always |
| 501 // eg: Logitech Notebook. This may be due to a bug in that API | 497 // eg: Logitech Notebook. This may be due to a bug in that API |
| 502 // because GetFrameRateList array is reversed in the above camera. So | 498 // because GetFrameRateList array is reversed in the above camera. So |
| 503 // a util method written. Can't assume the first value will return | 499 // a util method written. Can't assume the first value will return |
| 504 // the max fps. | 500 // the max fps. |
| 505 hr = video_control->GetFrameRateList(output_capture_pin_, i, size, | 501 hr = video_control->GetFrameRateList( |
| 506 &list_size, &max_fps); | 502 output_capture_pin_, stream_index, size, &list_size, &max_fps); |
| 507 // Sometimes |list_size| will be > 0, but max_fps will be NULL. Some | 503 // 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 | 504 // drivers may return an HRESULT of S_FALSE which SUCCEEDED() translates |
| 509 // into success, so explicitly check S_OK. See http://crbug.com/306237. | 505 // into success, so explicitly check S_OK. See http://crbug.com/306237. |
| 510 if (hr == S_OK && list_size > 0 && max_fps) { | 506 if (hr == S_OK && list_size > 0 && max_fps) { |
| 511 time_per_frame = *std::min_element(max_fps.get(), | 507 time_per_frame = *std::min_element(max_fps.get(), |
| 512 max_fps.get() + list_size); | 508 max_fps.get() + list_size); |
| 513 } | 509 } |
| 514 } | 510 } |
| 515 | 511 |
| 516 capability.supported_format.frame_rate = | 512 format.frame_rate = |
| 517 (time_per_frame > 0) | 513 (time_per_frame > 0) |
| 518 ? (kSecondsToReferenceTime / static_cast<float>(time_per_frame)) | 514 ? (kSecondsToReferenceTime / static_cast<float>(time_per_frame)) |
| 519 : 0.0; | 515 : 0.0; |
| 520 | 516 |
| 521 // DirectShow works at the moment only on integer frame_rate but the | 517 capabilities_.push_back(VideoCaptureCapabilityWin(stream_index, format)); |
| 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 } | 518 } |
| 528 } | 519 } |
| 529 | 520 |
| 530 return !capabilities_.empty(); | 521 return !capabilities_.empty(); |
| 531 } | 522 } |
| 532 | 523 |
| 533 // Set the power line frequency removal in |capture_filter_| if available. | 524 // Set the power line frequency removal in |capture_filter_| if available. |
| 534 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter() { | 525 void VideoCaptureDeviceWin::SetAntiFlickerInCaptureFilter() { |
| 535 const int power_line_frequency = GetPowerLineFrequencyForLocation(); | 526 const int power_line_frequency = GetPowerLineFrequencyForLocation(); |
| 536 if (power_line_frequency != kPowerLine50Hz && | 527 if (power_line_frequency != kPowerLine50Hz && |
| (...skipping 23 matching lines...) Expand all Loading... |
| 560 DVLOG(2) << "Anti-flicker setting not supported."; | 551 DVLOG(2) << "Anti-flicker setting not supported."; |
| 561 } | 552 } |
| 562 } | 553 } |
| 563 | 554 |
| 564 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { | 555 void VideoCaptureDeviceWin::SetErrorState(const std::string& reason) { |
| 565 DCHECK(CalledOnValidThread()); | 556 DCHECK(CalledOnValidThread()); |
| 566 state_ = kError; | 557 state_ = kError; |
| 567 client_->OnError(reason); | 558 client_->OnError(reason); |
| 568 } | 559 } |
| 569 } // namespace media | 560 } // namespace media |
| OLD | NEW |