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 |