Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(523)

Side by Side Diff: media/capture/video/win/video_capture_device_win.cc

Issue 2873143002: Image Capture: wire setPhotoOptions() for Win (Closed)
Patch Set: robliao@s comments, rebase and added capabilities width/height reading Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/capture/video/win/video_capture_device_win.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/capture/video/win/video_capture_device_win.h" 5 #include "media/capture/video/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 #include <objbase.h> 9 #include <objbase.h>
10 #include <vidcap.h>
11 10
12 #include <algorithm> 11 #include <algorithm>
13 #include <list> 12 #include <list>
14 #include <utility> 13 #include <utility>
15 14
16 #include "base/macros.h" 15 #include "base/macros.h"
17 #include "base/strings/sys_string_conversions.h" 16 #include "base/strings/sys_string_conversions.h"
18 #include "base/win/scoped_co_mem.h" 17 #include "base/win/scoped_co_mem.h"
19 #include "base/win/scoped_variant.h" 18 #include "base/win/scoped_variant.h"
20 #include "media/base/timestamp_constants.h" 19 #include "media/base/timestamp_constants.h"
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 void VideoCaptureDeviceWin::ScopedMediaType::DeleteMediaType( 258 void VideoCaptureDeviceWin::ScopedMediaType::DeleteMediaType(
260 AM_MEDIA_TYPE* mt) { 259 AM_MEDIA_TYPE* mt) {
261 if (mt != NULL) { 260 if (mt != NULL) {
262 FreeMediaType(mt); 261 FreeMediaType(mt);
263 CoTaskMemFree(mt); 262 CoTaskMemFree(mt);
264 } 263 }
265 } 264 }
266 265
267 VideoCaptureDeviceWin::VideoCaptureDeviceWin( 266 VideoCaptureDeviceWin::VideoCaptureDeviceWin(
268 const VideoCaptureDeviceDescriptor& device_descriptor) 267 const VideoCaptureDeviceDescriptor& device_descriptor)
269 : device_descriptor_(device_descriptor), state_(kIdle) { 268 : device_descriptor_(device_descriptor),
269 state_(kIdle),
270 white_balance_mode_manual_(false),
271 exposure_mode_manual_(false) {
270 // TODO(mcasas): Check that CoInitializeEx() has been called with the 272 // TODO(mcasas): Check that CoInitializeEx() has been called with the
271 // appropriate Apartment model, i.e., Single Threaded. 273 // appropriate Apartment model, i.e., Single Threaded.
272 } 274 }
273 275
274 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() { 276 VideoCaptureDeviceWin::~VideoCaptureDeviceWin() {
275 DCHECK(thread_checker_.CalledOnValidThread()); 277 DCHECK(thread_checker_.CalledOnValidThread());
276 if (media_control_.Get()) 278 if (media_control_.Get())
277 media_control_->Stop(); 279 media_control_->Stop();
278 280
279 if (graph_builder_.Get()) { 281 if (graph_builder_.Get()) {
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // Set the sink filter to request this format. 426 // Set the sink filter to request this format.
425 sink_filter_->SetRequestedMediaFormat( 427 sink_filter_->SetRequestedMediaFormat(
426 found_capability.supported_format.pixel_format, frame_rate, 428 found_capability.supported_format.pixel_format, frame_rate,
427 found_capability.info_header); 429 found_capability.info_header);
428 // Order the capture device to use this format. 430 // Order the capture device to use this format.
429 hr = stream_config->SetFormat(media_type.get()); 431 hr = stream_config->SetFormat(media_type.get());
430 if (FAILED(hr)) { 432 if (FAILED(hr)) {
431 SetErrorState(FROM_HERE, "Failed to set capture device output format", hr); 433 SetErrorState(FROM_HERE, "Failed to set capture device output format", hr);
432 return; 434 return;
433 } 435 }
436 current_capture_format_ = found_capability.supported_format;
434 437
435 SetAntiFlickerInCaptureFilter(params); 438 SetAntiFlickerInCaptureFilter(params);
436 439
437 if (media_type->subtype == kMediaSubTypeHDYC) { 440 if (media_type->subtype == kMediaSubTypeHDYC) {
438 // HDYC pixel format, used by the DeckLink capture card, needs an AVI 441 // HDYC pixel format, used by the DeckLink capture card, needs an AVI
439 // decompressor filter after source, let |graph_builder_| add it. 442 // decompressor filter after source, let |graph_builder_| add it.
440 hr = graph_builder_->Connect(output_capture_pin_.Get(), 443 hr = graph_builder_->Connect(output_capture_pin_.Get(),
441 input_sink_pin_.Get()); 444 input_sink_pin_.Get());
442 } else { 445 } else {
443 hr = graph_builder_->ConnectDirect(output_capture_pin_.Get(), 446 hr = graph_builder_->ConnectDirect(output_capture_pin_.Get(),
(...skipping 13 matching lines...) Expand all
457 460
458 // Start capturing. 461 // Start capturing.
459 hr = media_control_->Run(); 462 hr = media_control_->Run();
460 if (FAILED(hr)) { 463 if (FAILED(hr)) {
461 SetErrorState(FROM_HERE, "Failed to start the Capture device.", hr); 464 SetErrorState(FROM_HERE, "Failed to start the Capture device.", hr);
462 return; 465 return;
463 } 466 }
464 467
465 client_->OnStarted(); 468 client_->OnStarted();
466 state_ = kCapturing; 469 state_ = kCapturing;
467 }
468
469 void VideoCaptureDeviceWin::StopAndDeAllocate() {
470 DCHECK(thread_checker_.CalledOnValidThread());
471 if (state_ != kCapturing)
472 return;
473
474 HRESULT hr = media_control_->Stop();
475 if (FAILED(hr)) {
476 SetErrorState(FROM_HERE, "Failed to stop the capture graph.", hr);
477 return;
478 }
479
480 graph_builder_->Disconnect(output_capture_pin_.Get());
481 graph_builder_->Disconnect(input_sink_pin_.Get());
482
483 client_.reset();
484 state_ = kIdle;
485 }
486
487 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) {
488 DCHECK(thread_checker_.CalledOnValidThread());
489 // DirectShow has other means of capturing still pictures, e.g. connecting a
490 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This
491 // way, however, is not widespread and proves too cumbersome, so we just grab
492 // the next captured frame instead.
493 take_photo_callbacks_.push(std::move(callback));
494 }
495
496 void VideoCaptureDeviceWin::GetPhotoCapabilities(
497 GetPhotoCapabilitiesCallback callback) {
498 DCHECK(thread_checker_.CalledOnValidThread());
499 470
500 base::win::ScopedComPtr<IKsTopologyInfo> info; 471 base::win::ScopedComPtr<IKsTopologyInfo> info;
501 HRESULT hr = capture_filter_.CopyTo(info.GetAddressOf()); 472 hr = capture_filter_.CopyTo(info.GetAddressOf());
502 if (FAILED(hr)) { 473 if (FAILED(hr)) {
503 SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr); 474 SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr);
504 return; 475 return;
505 } 476 }
506 477
507 DWORD num_nodes = 0; 478 DWORD num_nodes = 0;
508 hr = info->get_NumNodes(&num_nodes); 479 hr = info->get_NumNodes(&num_nodes);
509 if (FAILED(hr)) { 480 if (FAILED(hr)) {
510 SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr); 481 SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr);
511 return; 482 return;
512 } 483 }
513 484
514 // Every UVC camera is expected to have a single ICameraControl and a single 485 // Every UVC camera is expected to have a single ICameraControl and a single
515 // IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones. 486 // IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones.
516 GUID node_type; 487 GUID node_type;
517 base::win::ScopedComPtr<ICameraControl> camera_control;
518 for (size_t i = 0; i < num_nodes; i++) { 488 for (size_t i = 0; i < num_nodes; i++) {
519 info->get_NodeType(i, &node_type); 489 info->get_NodeType(i, &node_type);
520 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) { 490 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) {
521 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&camera_control)); 491 hr = info->CreateNodeInstance(
492 i, IID_PPV_ARGS(camera_control_.GetAddressOf()));
robliao 2017/05/12 19:34:30 IID_PPV_ARGS(&camera_control) should continue to w
mcasas 2017/05/12 21:27:04 Oops, wrong rebase. Reverted and still working.
522 if (SUCCEEDED(hr)) 493 if (SUCCEEDED(hr))
523 break; 494 break;
524 SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr); 495 SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr);
525 return; 496 return;
526 } 497 }
527 } 498 }
528 if (!camera_control)
529 return;
530 base::win::ScopedComPtr<IVideoProcAmp> video_control;
531 for (size_t i = 0; i < num_nodes; i++) { 499 for (size_t i = 0; i < num_nodes; i++) {
532 info->get_NodeType(i, &node_type); 500 info->get_NodeType(i, &node_type);
533 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) { 501 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) {
534 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(&video_control)); 502 hr = info->CreateNodeInstance(
503 i, IID_PPV_ARGS(video_control_.GetAddressOf()));
535 if (SUCCEEDED(hr)) 504 if (SUCCEEDED(hr))
536 break; 505 break;
537 SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr); 506 SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr);
538 return; 507 return;
539 } 508 }
540 } 509 }
541 if (!video_control) 510 }
511
512 void VideoCaptureDeviceWin::StopAndDeAllocate() {
513 DCHECK(thread_checker_.CalledOnValidThread());
514 if (state_ != kCapturing)
515 return;
516
517 HRESULT hr = media_control_->Stop();
518 if (FAILED(hr)) {
519 SetErrorState(FROM_HERE, "Failed to stop the capture graph.", hr);
520 return;
521 }
522
523 graph_builder_->Disconnect(output_capture_pin_.Get());
524 graph_builder_->Disconnect(input_sink_pin_.Get());
525
526 client_.reset();
527 state_ = kIdle;
528 }
529
530 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) {
531 DCHECK(thread_checker_.CalledOnValidThread());
532 // DirectShow has other means of capturing still pictures, e.g. connecting a
533 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This
534 // way, however, is not widespread and proves too cumbersome, so we just grab
535 // the next captured frame instead.
536 take_photo_callbacks_.push(std::move(callback));
537 }
538
539 void VideoCaptureDeviceWin::GetPhotoCapabilities(
540 GetPhotoCapabilitiesCallback callback) {
541 DCHECK(thread_checker_.CalledOnValidThread());
542
543 if (!camera_control_ || !video_control_)
542 return; 544 return;
543 545
544 auto photo_capabilities = mojom::PhotoCapabilities::New(); 546 auto photo_capabilities = mojom::PhotoCapabilities::New();
545 547
546 photo_capabilities->exposure_compensation = RetrieveControlRangeAndCurrent( 548 photo_capabilities->exposure_compensation = RetrieveControlRangeAndCurrent(
547 [camera_control](auto... args) { 549 [this](auto... args) {
548 return camera_control->getRange_Exposure(args...); 550 return this->camera_control_->getRange_Exposure(args...);
549 }, 551 },
550 [camera_control](auto... args) { 552 [this](auto... args) {
551 return camera_control->get_Exposure(args...); 553 return this->camera_control_->get_Exposure(args...);
552 }, 554 },
553 &photo_capabilities->supported_exposure_modes, 555 &photo_capabilities->supported_exposure_modes,
554 &photo_capabilities->current_exposure_mode); 556 &photo_capabilities->current_exposure_mode);
555 557
556 photo_capabilities->color_temperature = RetrieveControlRangeAndCurrent( 558 photo_capabilities->color_temperature = RetrieveControlRangeAndCurrent(
557 [video_control](auto... args) { 559 [this](auto... args) {
558 return video_control->getRange_WhiteBalance(args...); 560 return this->video_control_->getRange_WhiteBalance(args...);
559 }, 561 },
560 [video_control](auto... args) { 562 [this](auto... args) {
561 return video_control->get_WhiteBalance(args...); 563 return this->video_control_->get_WhiteBalance(args...);
562 }, 564 },
563 &photo_capabilities->supported_white_balance_modes, 565 &photo_capabilities->supported_white_balance_modes,
564 &photo_capabilities->current_white_balance_mode); 566 &photo_capabilities->current_white_balance_mode);
565 567
566 // Ignore the returned Focus control range and status. 568 // Ignore the returned Focus control range and status.
567 RetrieveControlRangeAndCurrent( 569 RetrieveControlRangeAndCurrent(
568 [camera_control](auto... args) { 570 [this](auto... args) {
569 return camera_control->getRange_Focus(args...); 571 return this->camera_control_->getRange_Focus(args...);
570 }, 572 },
571 [camera_control](auto... args) { 573 [this](auto... args) {
572 return camera_control->get_Focus(args...); 574 return this->camera_control_->get_Focus(args...);
573 }, 575 },
574 &photo_capabilities->supported_focus_modes, 576 &photo_capabilities->supported_focus_modes,
575 &photo_capabilities->current_focus_mode); 577 &photo_capabilities->current_focus_mode);
576 578
577 photo_capabilities->iso = mojom::Range::New(); 579 photo_capabilities->iso = mojom::Range::New();
578 580
579 photo_capabilities->brightness = RetrieveControlRangeAndCurrent( 581 photo_capabilities->brightness = RetrieveControlRangeAndCurrent(
580 [video_control](auto... args) { 582 [this](auto... args) {
581 return video_control->getRange_Brightness(args...); 583 return this->video_control_->getRange_Brightness(args...);
582 }, 584 },
583 [video_control](auto... args) { 585 [this](auto... args) {
584 return video_control->get_Brightness(args...); 586 return this->video_control_->get_Brightness(args...);
585 }); 587 });
586 photo_capabilities->contrast = RetrieveControlRangeAndCurrent( 588 photo_capabilities->contrast = RetrieveControlRangeAndCurrent(
587 [video_control](auto... args) { 589 [this](auto... args) {
588 return video_control->getRange_Contrast(args...); 590 return this->video_control_->getRange_Contrast(args...);
589 }, 591 },
590 [video_control](auto... args) { 592 [this](auto... args) {
591 return video_control->get_Contrast(args...); 593 return this->video_control_->get_Contrast(args...);
592 }); 594 });
593 photo_capabilities->saturation = RetrieveControlRangeAndCurrent( 595 photo_capabilities->saturation = RetrieveControlRangeAndCurrent(
594 [video_control](auto... args) { 596 [this](auto... args) {
595 return video_control->getRange_Saturation(args...); 597 return this->video_control_->getRange_Saturation(args...);
596 }, 598 },
597 [video_control](auto... args) { 599 [this](auto... args) {
598 return video_control->get_Saturation(args...); 600 return this->video_control_->get_Saturation(args...);
599 }); 601 });
600 photo_capabilities->sharpness = RetrieveControlRangeAndCurrent( 602 photo_capabilities->sharpness = RetrieveControlRangeAndCurrent(
601 [video_control](auto... args) { 603 [this](auto... args) {
602 return video_control->getRange_Sharpness(args...); 604 return this->video_control_->getRange_Sharpness(args...);
603 }, 605 },
604 [video_control](auto... args) { 606 [this](auto... args) {
605 return video_control->get_Sharpness(args...); 607 return this->video_control_->get_Sharpness(args...);
606 }); 608 });
607 609
608 photo_capabilities->zoom = RetrieveControlRangeAndCurrent( 610 photo_capabilities->zoom = RetrieveControlRangeAndCurrent(
609 [camera_control](auto... args) { 611 [this](auto... args) {
610 return camera_control->getRange_Zoom(args...); 612 return this->camera_control_->getRange_Zoom(args...);
611 }, 613 },
612 [camera_control](auto... args) { 614 [this](auto... args) {
613 return camera_control->get_Zoom(args...); 615 return this->camera_control_->get_Zoom(args...);
614 }); 616 });
615 617
616 photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER; 618 photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER;
617 photo_capabilities->height = mojom::Range::New(); 619 photo_capabilities->height = mojom::Range::New(
618 photo_capabilities->width = mojom::Range::New(); 620 capture_format_.frame_size.height(), capture_format_.frame_size.height(),
621 capture_format_.frame_size.height(), 0 /* step */);
622 photo_capabilities->width = mojom::Range::New(
623 capture_format_.frame_size.width(), capture_format_.frame_size.width(),
624 capture_format_.frame_size.width(), 0 /* step */);
619 photo_capabilities->torch = false; 625 photo_capabilities->torch = false;
620 626
621 callback.Run(std::move(photo_capabilities)); 627 callback.Run(std::move(photo_capabilities));
622 } 628 }
623 629
630 void VideoCaptureDeviceWin::SetPhotoOptions(
631 mojom::PhotoSettingsPtr settings,
632 VideoCaptureDevice::SetPhotoOptionsCallback callback) {
633 DCHECK(thread_checker_.CalledOnValidThread());
634
635 if (!camera_control_ || !video_control_)
636 return;
637
638 if (settings->has_zoom) {
639 HRESULT hr =
640 camera_control_->put_Zoom(settings->zoom, CameraControl_Flags_Manual);
641 DLOG_IF_FAILED_WITH_HRESULT("Zoom config failed", hr);
642 }
643
644 if (settings->has_white_balance_mode) {
645 if (settings->white_balance_mode == mojom::MeteringMode::CONTINUOUS) {
646 HRESULT hr =
647 video_control_->put_WhiteBalance(0L, VideoProcAmp_Flags_Auto);
648 DLOG_IF_FAILED_WITH_HRESULT("Auto white balance config failed", hr);
649
650 white_balance_mode_manual_ = false;
651 } else {
652 white_balance_mode_manual_ = true;
653 }
654 }
655 if (white_balance_mode_manual_ && settings->has_color_temperature) {
656 HRESULT hr = video_control_->put_WhiteBalance(settings->color_temperature,
657 CameraControl_Flags_Manual);
658 DLOG_IF_FAILED_WITH_HRESULT("Color temperature config failed", hr);
659 }
660
661 if (settings->has_exposure_mode) {
662 if (settings->exposure_mode == mojom::MeteringMode::CONTINUOUS) {
663 HRESULT hr = camera_control_->put_Exposure(0L, VideoProcAmp_Flags_Auto);
664 DLOG_IF_FAILED_WITH_HRESULT("Auto exposure config failed", hr);
665
666 exposure_mode_manual_ = false;
667 } else {
668 exposure_mode_manual_ = true;
669 }
670 }
671 if (exposure_mode_manual_ && settings->has_exposure_compensation) {
672 HRESULT hr = camera_control_->put_Exposure(settings->exposure_compensation,
673 CameraControl_Flags_Manual);
674 DLOG_IF_FAILED_WITH_HRESULT("Exposure Compensation config failed", hr);
675 }
676
677 if (settings->has_brightness) {
678 HRESULT hr = video_control_->put_Brightness(settings->brightness,
679 CameraControl_Flags_Manual);
680 DLOG_IF_FAILED_WITH_HRESULT("Brightness config failed", hr);
681 }
682 if (settings->has_contrast) {
683 HRESULT hr = video_control_->put_Contrast(settings->contrast,
684 CameraControl_Flags_Manual);
685 DLOG_IF_FAILED_WITH_HRESULT("Contrast config failed", hr);
686 }
687 if (settings->has_saturation) {
688 HRESULT hr = video_control_->put_Saturation(settings->saturation,
689 CameraControl_Flags_Manual);
690 DLOG_IF_FAILED_WITH_HRESULT("Saturation config failed", hr);
691 }
692 if (settings->has_sharpness) {
693 HRESULT hr = video_control_->put_Sharpness(settings->sharpness,
694 CameraControl_Flags_Manual);
695 DLOG_IF_FAILED_WITH_HRESULT("Sharpness config failed", hr);
696 }
697
698 callback.Run(true);
robliao 2017/05/12 19:34:30 Should this be called synchronously or should it b
mcasas 2017/05/12 21:27:04 This callback is a sophisticated ScopedResultCallb
699 }
624 // Implements SinkFilterObserver::SinkFilterObserver. 700 // Implements SinkFilterObserver::SinkFilterObserver.
625 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer, 701 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer,
626 int length, 702 int length,
627 const VideoCaptureFormat& format, 703 const VideoCaptureFormat& format,
628 base::TimeDelta timestamp) { 704 base::TimeDelta timestamp) {
629 if (first_ref_time_.is_null()) 705 if (first_ref_time_.is_null())
630 first_ref_time_ = base::TimeTicks::Now(); 706 first_ref_time_ = base::TimeTicks::Now();
631 707
632 // There is a chance that the platform does not provide us with the timestamp, 708 // There is a chance that the platform does not provide us with the timestamp,
633 // in which case, we use reference time to calculate a timestamp. 709 // in which case, we use reference time to calculate a timestamp.
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 void VideoCaptureDeviceWin::SetErrorState( 834 void VideoCaptureDeviceWin::SetErrorState(
759 const tracked_objects::Location& from_here, 835 const tracked_objects::Location& from_here,
760 const std::string& reason, 836 const std::string& reason,
761 HRESULT hr) { 837 HRESULT hr) {
762 DCHECK(thread_checker_.CalledOnValidThread()); 838 DCHECK(thread_checker_.CalledOnValidThread());
763 DLOG_IF_FAILED_WITH_HRESULT(reason, hr); 839 DLOG_IF_FAILED_WITH_HRESULT(reason, hr);
764 state_ = kError; 840 state_ = kError;
765 client_->OnError(from_here, reason); 841 client_->OnError(from_here, reason);
766 } 842 }
767 } // namespace media 843 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/win/video_capture_device_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698