| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <list> | 8 #include <list> |
| 9 | 9 |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 CoTaskMemFree(mt); | 141 CoTaskMemFree(mt); |
| 142 } | 142 } |
| 143 } | 143 } |
| 144 | 144 |
| 145 // Help structure used for comparing video capture capabilities. | 145 // Help structure used for comparing video capture capabilities. |
| 146 struct ResolutionDiff { | 146 struct ResolutionDiff { |
| 147 int capability_index; | 147 int capability_index; |
| 148 int diff_height; | 148 int diff_height; |
| 149 int diff_width; | 149 int diff_width; |
| 150 int diff_frame_rate; | 150 int diff_frame_rate; |
| 151 media::VideoCaptureDevice::Format color; | 151 media::VideoCaptureCapability::Format color; |
| 152 }; | 152 }; |
| 153 | 153 |
| 154 bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) { | 154 bool CompareHeight(const ResolutionDiff& item1, const ResolutionDiff& item2) { |
| 155 return abs(item1.diff_height) < abs(item2.diff_height); | 155 return abs(item1.diff_height) < abs(item2.diff_height); |
| 156 } | 156 } |
| 157 | 157 |
| 158 bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { | 158 bool CompareWidth(const ResolutionDiff& item1, const ResolutionDiff& item2) { |
| 159 return abs(item1.diff_width) < abs(item2.diff_width); | 159 return abs(item1.diff_width) < abs(item2.diff_width); |
| 160 } | 160 } |
| 161 | 161 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 int height, | 331 int height, |
| 332 int frame_rate, | 332 int frame_rate, |
| 333 VideoCaptureDevice::EventHandler* observer) { | 333 VideoCaptureDevice::EventHandler* observer) { |
| 334 if (state_ != kIdle) | 334 if (state_ != kIdle) |
| 335 return; | 335 return; |
| 336 | 336 |
| 337 observer_ = observer; | 337 observer_ = observer; |
| 338 // Get the camera capability that best match the requested resolution. | 338 // Get the camera capability that best match the requested resolution. |
| 339 const int capability_index = GetBestMatchedCapability(width, height, | 339 const int capability_index = GetBestMatchedCapability(width, height, |
| 340 frame_rate); | 340 frame_rate); |
| 341 Capability capability = capabilities_[capability_index]; | 341 VideoCaptureCapability capability = capabilities_[capability_index]; |
| 342 | 342 |
| 343 // Reduce the frame rate if the requested frame rate is lower | 343 // Reduce the frame rate if the requested frame rate is lower |
| 344 // than the capability. | 344 // than the capability. |
| 345 if (capability.frame_rate > frame_rate) | 345 if (capability.frame_rate > frame_rate) |
| 346 capability.frame_rate = frame_rate; | 346 capability.frame_rate = frame_rate; |
| 347 | 347 |
| 348 AM_MEDIA_TYPE* pmt = NULL; | 348 AM_MEDIA_TYPE* pmt = NULL; |
| 349 VIDEO_STREAM_CONFIG_CAPS caps; | 349 VIDEO_STREAM_CONFIG_CAPS caps; |
| 350 | 350 |
| 351 ScopedComPtr<IAMStreamConfig> stream_config; | 351 ScopedComPtr<IAMStreamConfig> stream_config; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 366 } | 366 } |
| 367 // Set the sink filter to request this capability. | 367 // Set the sink filter to request this capability. |
| 368 sink_filter_->SetRequestedMediaCapability(capability); | 368 sink_filter_->SetRequestedMediaCapability(capability); |
| 369 // Order the capture device to use this capability. | 369 // Order the capture device to use this capability. |
| 370 hr = stream_config->SetFormat(pmt); | 370 hr = stream_config->SetFormat(pmt); |
| 371 } | 371 } |
| 372 | 372 |
| 373 if (FAILED(hr)) | 373 if (FAILED(hr)) |
| 374 SetErrorState("Failed to set capture device output format"); | 374 SetErrorState("Failed to set capture device output format"); |
| 375 | 375 |
| 376 if (capability.color == VideoCaptureDevice::kMJPEG && !mjpg_filter_.get()) { | 376 if (capability.color == VideoCaptureCapability::kMJPEG && |
| 377 !mjpg_filter_.get()) { |
| 377 // Create MJPG filter if we need it. | 378 // Create MJPG filter if we need it. |
| 378 hr = mjpg_filter_.CreateInstance(CLSID_MjpegDec, NULL, CLSCTX_INPROC); | 379 hr = mjpg_filter_.CreateInstance(CLSID_MjpegDec, NULL, CLSCTX_INPROC); |
| 379 | 380 |
| 380 if (SUCCEEDED(hr)) { | 381 if (SUCCEEDED(hr)) { |
| 381 GetPin(mjpg_filter_, PINDIR_INPUT, GUID_NULL, input_mjpg_pin_.Receive()); | 382 GetPin(mjpg_filter_, PINDIR_INPUT, GUID_NULL, input_mjpg_pin_.Receive()); |
| 382 GetPin(mjpg_filter_, PINDIR_OUTPUT, GUID_NULL, | 383 GetPin(mjpg_filter_, PINDIR_OUTPUT, GUID_NULL, |
| 383 output_mjpg_pin_.Receive()); | 384 output_mjpg_pin_.Receive()); |
| 384 hr = graph_builder_->AddFilter(mjpg_filter_, NULL); | 385 hr = graph_builder_->AddFilter(mjpg_filter_, NULL); |
| 385 } | 386 } |
| 386 | 387 |
| 387 if (FAILED(hr)) { | 388 if (FAILED(hr)) { |
| 388 mjpg_filter_.Release(); | 389 mjpg_filter_.Release(); |
| 389 input_mjpg_pin_.Release(); | 390 input_mjpg_pin_.Release(); |
| 390 output_mjpg_pin_.Release(); | 391 output_mjpg_pin_.Release(); |
| 391 } | 392 } |
| 392 } | 393 } |
| 393 | 394 |
| 394 if (capability.color == VideoCaptureDevice::kMJPEG && mjpg_filter_.get()) { | 395 if (capability.color == VideoCaptureCapability::kMJPEG && |
| 396 mjpg_filter_.get()) { |
| 395 // Connect the camera to the MJPEG decoder. | 397 // Connect the camera to the MJPEG decoder. |
| 396 hr = graph_builder_->ConnectDirect(output_capture_pin_, input_mjpg_pin_, | 398 hr = graph_builder_->ConnectDirect(output_capture_pin_, input_mjpg_pin_, |
| 397 NULL); | 399 NULL); |
| 398 // Connect the MJPEG filter to the Capture filter. | 400 // Connect the MJPEG filter to the Capture filter. |
| 399 hr += graph_builder_->ConnectDirect(output_mjpg_pin_, input_sink_pin_, | 401 hr += graph_builder_->ConnectDirect(output_mjpg_pin_, input_sink_pin_, |
| 400 NULL); | 402 NULL); |
| 401 } else { | 403 } else { |
| 402 hr = graph_builder_->ConnectDirect(output_capture_pin_, input_sink_pin_, | 404 hr = graph_builder_->ConnectDirect(output_capture_pin_, input_sink_pin_, |
| 403 NULL); | 405 NULL); |
| 404 } | 406 } |
| 405 | 407 |
| 406 if (FAILED(hr)) { | 408 if (FAILED(hr)) { |
| 407 SetErrorState("Failed to connect the Capture graph."); | 409 SetErrorState("Failed to connect the Capture graph."); |
| 408 return; | 410 return; |
| 409 } | 411 } |
| 410 | 412 |
| 411 hr = media_control_->Pause(); | 413 hr = media_control_->Pause(); |
| 412 if (FAILED(hr)) { | 414 if (FAILED(hr)) { |
| 413 SetErrorState("Failed to Pause the Capture device. " | 415 SetErrorState("Failed to Pause the Capture device. " |
| 414 "Is it already occupied?"); | 416 "Is it already occupied?"); |
| 415 return; | 417 return; |
| 416 } | 418 } |
| 417 | 419 |
| 418 // Get the capability back from the sink filter after the filter have been | 420 // Get the capability back from the sink filter after the filter have been |
| 419 // connected. | 421 // connected. |
| 420 const Capability& used_capability = sink_filter_->ResultingCapability(); | 422 const VideoCaptureCapability& used_capability |
| 423 = sink_filter_->ResultingCapability(); |
| 421 observer_->OnFrameInfo(used_capability); | 424 observer_->OnFrameInfo(used_capability); |
| 422 | 425 |
| 423 state_ = kAllocated; | 426 state_ = kAllocated; |
| 424 } | 427 } |
| 425 | 428 |
| 426 void VideoCaptureDeviceWin::Start() { | 429 void VideoCaptureDeviceWin::Start() { |
| 427 if (state_ != kAllocated) | 430 if (state_ != kAllocated) |
| 428 return; | 431 return; |
| 429 | 432 |
| 430 HRESULT hr = media_control_->Run(); | 433 HRESULT hr = media_control_->Run(); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 for (int i = 0; i < count; ++i) { | 511 for (int i = 0; i < count; ++i) { |
| 509 hr = stream_config->GetStreamCaps(i, &media_type, | 512 hr = stream_config->GetStreamCaps(i, &media_type, |
| 510 reinterpret_cast<BYTE*>(&caps)); | 513 reinterpret_cast<BYTE*>(&caps)); |
| 511 if (FAILED(hr)) { | 514 if (FAILED(hr)) { |
| 512 DVLOG(2) << "Failed to GetStreamCaps"; | 515 DVLOG(2) << "Failed to GetStreamCaps"; |
| 513 return false; | 516 return false; |
| 514 } | 517 } |
| 515 | 518 |
| 516 if (media_type->majortype == MEDIATYPE_Video && | 519 if (media_type->majortype == MEDIATYPE_Video && |
| 517 media_type->formattype == FORMAT_VideoInfo) { | 520 media_type->formattype == FORMAT_VideoInfo) { |
| 518 Capability capability; | 521 VideoCaptureCapability capability; |
| 519 REFERENCE_TIME time_per_frame = 0; | 522 REFERENCE_TIME time_per_frame = 0; |
| 520 | 523 |
| 521 VIDEOINFOHEADER* h = | 524 VIDEOINFOHEADER* h = |
| 522 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); | 525 reinterpret_cast<VIDEOINFOHEADER*>(media_type->pbFormat); |
| 523 capability.width = h->bmiHeader.biWidth; | 526 capability.width = h->bmiHeader.biWidth; |
| 524 capability.height = h->bmiHeader.biHeight; | 527 capability.height = h->bmiHeader.biHeight; |
| 525 time_per_frame = h->AvgTimePerFrame; | 528 time_per_frame = h->AvgTimePerFrame; |
| 526 | 529 |
| 527 // Try to get the max frame rate from IAMVideoControl. | 530 // Try to get the max frame rate from IAMVideoControl. |
| 528 if (video_control.get()) { | 531 if (video_control.get()) { |
| (...skipping 23 matching lines...) Expand all Loading... |
| 552 } | 555 } |
| 553 } else { | 556 } else { |
| 554 // Get frame rate from VIDEOINFOHEADER since IAMVideoControl is | 557 // Get frame rate from VIDEOINFOHEADER since IAMVideoControl is |
| 555 // not supported. | 558 // not supported. |
| 556 capability.frame_rate = (time_per_frame > 0) ? | 559 capability.frame_rate = (time_per_frame > 0) ? |
| 557 static_cast<int>(kSecondsToReferenceTime / time_per_frame) : 0; | 560 static_cast<int>(kSecondsToReferenceTime / time_per_frame) : 0; |
| 558 } | 561 } |
| 559 | 562 |
| 560 // We can't switch MEDIATYPE :~(. | 563 // We can't switch MEDIATYPE :~(. |
| 561 if (media_type->subtype == kMediaSubTypeI420) { | 564 if (media_type->subtype == kMediaSubTypeI420) { |
| 562 capability.color = VideoCaptureDevice::kI420; | 565 capability.color = VideoCaptureCapability::kI420; |
| 563 } else if (media_type->subtype == MEDIASUBTYPE_IYUV) { | 566 } else if (media_type->subtype == MEDIASUBTYPE_IYUV) { |
| 564 // This is identical to kI420. | 567 // This is identical to kI420. |
| 565 capability.color = VideoCaptureDevice::kI420; | 568 capability.color = VideoCaptureCapability::kI420; |
| 566 } else if (media_type->subtype == MEDIASUBTYPE_RGB24) { | 569 } else if (media_type->subtype == MEDIASUBTYPE_RGB24) { |
| 567 capability.color = VideoCaptureDevice::kRGB24; | 570 capability.color = VideoCaptureCapability::kRGB24; |
| 568 } else if (media_type->subtype == MEDIASUBTYPE_YUY2) { | 571 } else if (media_type->subtype == MEDIASUBTYPE_YUY2) { |
| 569 capability.color = VideoCaptureDevice::kYUY2; | 572 capability.color = VideoCaptureCapability::kYUY2; |
| 570 } else if (media_type->subtype == MEDIASUBTYPE_MJPG) { | 573 } else if (media_type->subtype == MEDIASUBTYPE_MJPG) { |
| 571 capability.color = VideoCaptureDevice::kMJPEG; | 574 capability.color = VideoCaptureCapability::kMJPEG; |
| 572 } else { | 575 } else { |
| 573 WCHAR guid_str[128]; | 576 WCHAR guid_str[128]; |
| 574 StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str)); | 577 StringFromGUID2(media_type->subtype, guid_str, arraysize(guid_str)); |
| 575 DVLOG(2) << "Device support unknown media type " << guid_str; | 578 DVLOG(2) << "Device support unknown media type " << guid_str; |
| 576 continue; | 579 continue; |
| 577 } | 580 } |
| 578 capabilities_[i] = capability; | 581 capabilities_[i] = capability; |
| 579 } | 582 } |
| 580 DeleteMediaType(media_type); | 583 DeleteMediaType(media_type); |
| 581 media_type = NULL; | 584 media_type = NULL; |
| 582 } | 585 } |
| 583 | 586 |
| 584 return capabilities_.size() > 0; | 587 return capabilities_.size() > 0; |
| 585 } | 588 } |
| 586 | 589 |
| 587 // Loops through the list of capabilities and returns an index of the best | 590 // Loops through the list of capabilities and returns an index of the best |
| 588 // matching capability. | 591 // matching capability. |
| 589 // The algorithm prioritize height, width, frame rate and color format in that | 592 // The algorithm prioritize height, width, frame rate and color format in that |
| 590 // order. | 593 // order. |
| 591 int VideoCaptureDeviceWin::GetBestMatchedCapability(int requested_width, | 594 int VideoCaptureDeviceWin::GetBestMatchedCapability(int requested_width, |
| 592 int requested_height, | 595 int requested_height, |
| 593 int requested_frame_rate) { | 596 int requested_frame_rate) { |
| 594 std::list<ResolutionDiff> diff_list; | 597 std::list<ResolutionDiff> diff_list; |
| 595 | 598 |
| 596 // Loop through the candidates to create a list of differentials between the | 599 // Loop through the candidates to create a list of differentials between the |
| 597 // requested resolution and the camera capability. | 600 // requested resolution and the camera capability. |
| 598 for (CapabilityMap::iterator iterator = capabilities_.begin(); | 601 for (CapabilityMap::iterator iterator = capabilities_.begin(); |
| 599 iterator != capabilities_.end(); | 602 iterator != capabilities_.end(); |
| 600 ++iterator) { | 603 ++iterator) { |
| 601 Capability capability = iterator->second; | 604 VideoCaptureCapability capability = iterator->second; |
| 602 | 605 |
| 603 ResolutionDiff diff; | 606 ResolutionDiff diff; |
| 604 diff.capability_index = iterator->first; | 607 diff.capability_index = iterator->first; |
| 605 diff.diff_width = capability.width - requested_width; | 608 diff.diff_width = capability.width - requested_width; |
| 606 diff.diff_height = capability.height - requested_height; | 609 diff.diff_height = capability.height - requested_height; |
| 607 diff.diff_frame_rate = capability.frame_rate - requested_frame_rate; | 610 diff.diff_frame_rate = capability.frame_rate - requested_frame_rate; |
| 608 diff.color = capability.color; | 611 diff.color = capability.color; |
| 609 diff_list.push_back(diff); | 612 diff_list.push_back(diff); |
| 610 } | 613 } |
| 611 | 614 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 649 return diff_list.front().capability_index; | 652 return diff_list.front().capability_index; |
| 650 } | 653 } |
| 651 | 654 |
| 652 void VideoCaptureDeviceWin::SetErrorState(const char* reason) { | 655 void VideoCaptureDeviceWin::SetErrorState(const char* reason) { |
| 653 DLOG(ERROR) << reason; | 656 DLOG(ERROR) << reason; |
| 654 state_ = kError; | 657 state_ = kError; |
| 655 observer_->OnError(); | 658 observer_->OnError(); |
| 656 } | 659 } |
| 657 | 660 |
| 658 } // namespace media | 661 } // namespace media |
| OLD | NEW |