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

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

Issue 2856893003: Image Capture: wire getCapabilities() in Windows (Closed)
Patch Set: Rebase: ScopedComPtr s/QueryInterface/CopyTo/ 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>
10 11
11 #include <algorithm> 12 #include <algorithm>
12 #include <list> 13 #include <list>
13 #include <utility> 14 #include <utility>
14 15
15 #include "base/macros.h" 16 #include "base/macros.h"
16 #include "base/strings/sys_string_conversions.h" 17 #include "base/strings/sys_string_conversions.h"
17 #include "base/win/scoped_co_mem.h" 18 #include "base/win/scoped_co_mem.h"
18 #include "base/win/scoped_variant.h" 19 #include "base/win/scoped_variant.h"
19 #include "media/base/timestamp_constants.h" 20 #include "media/base/timestamp_constants.h"
20 #include "media/capture/video/blob_utils.h" 21 #include "media/capture/video/blob_utils.h"
21 22
22 using base::win::ScopedCoMem; 23 using base::win::ScopedCoMem;
23 using base::win::ScopedComPtr; 24 using base::win::ScopedComPtr;
24 using base::win::ScopedVariant; 25 using base::win::ScopedVariant;
25 26
26 namespace media { 27 namespace media {
27 28
28 #if DCHECK_IS_ON() 29 #if DCHECK_IS_ON()
29 #define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \ 30 #define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \
30 { \ 31 { \
31 DLOG_IF(ERROR, FAILED(hr)) << (message) << ": " \ 32 DLOG_IF(ERROR, FAILED(hr)) \
32 << logging::SystemErrorCodeToString(hr); \ 33 << (message) << ": " << logging::SystemErrorCodeToString(hr); \
33 } 34 }
34 #else 35 #else
35 #define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \ 36 #define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \
36 {} 37 {}
37 #endif 38 #endif
38 39
39 // Check if a Pin matches a category. 40 // Check if a Pin matches a category.
40 bool PinMatchesCategory(IPin* pin, REFGUID category) { 41 bool PinMatchesCategory(IPin* pin, REFGUID category) {
41 DCHECK(pin); 42 DCHECK(pin);
42 bool found = false; 43 bool found = false;
(...skipping 12 matching lines...) Expand all
55 } 56 }
56 57
57 // Check if a Pin's MediaType matches a given |major_type|. 58 // Check if a Pin's MediaType matches a given |major_type|.
58 bool PinMatchesMajorType(IPin* pin, REFGUID major_type) { 59 bool PinMatchesMajorType(IPin* pin, REFGUID major_type) {
59 DCHECK(pin); 60 DCHECK(pin);
60 AM_MEDIA_TYPE connection_media_type; 61 AM_MEDIA_TYPE connection_media_type;
61 const HRESULT hr = pin->ConnectionMediaType(&connection_media_type); 62 const HRESULT hr = pin->ConnectionMediaType(&connection_media_type);
62 return SUCCEEDED(hr) && connection_media_type.majortype == major_type; 63 return SUCCEEDED(hr) && connection_media_type.majortype == major_type;
63 } 64 }
64 65
66 // Retrieves the control range and value using the provided getters, and
67 // optionally returns the associated supported and current mode.
68 template <typename RangeGetter, typename ValueGetter>
69 mojom::RangePtr RetrieveControlRangeAndCurrent(
70 RangeGetter range_getter,
71 ValueGetter value_getter,
72 std::vector<mojom::MeteringMode>* supported_modes = nullptr,
73 mojom::MeteringMode* current_mode = nullptr) {
74 auto control_range = mojom::Range::New();
75 long min, max, step, default_value, flags;
76 HRESULT hr = range_getter(&min, &max, &step, &default_value, &flags);
77 DLOG_IF_FAILED_WITH_HRESULT("Control range reading failed", hr);
78 if (SUCCEEDED(hr)) {
79 control_range->min = min;
80 control_range->max = max;
81 control_range->step = step;
82 if (supported_modes != nullptr) {
83 if (flags && CameraControl_Flags_Auto)
84 supported_modes->push_back(mojom::MeteringMode::CONTINUOUS);
85 if (flags && CameraControl_Flags_Manual)
86 supported_modes->push_back(mojom::MeteringMode::MANUAL);
87 }
88 }
89 long current;
90 hr = value_getter(&current, &flags);
91 DLOG_IF_FAILED_WITH_HRESULT("Control value reading failed", hr);
92 if (SUCCEEDED(hr)) {
93 control_range->current = current;
94 if (current_mode != nullptr) {
95 if (flags && CameraControl_Flags_Auto)
96 *current_mode = mojom::MeteringMode::CONTINUOUS;
97 else if (flags && CameraControl_Flags_Manual)
98 *current_mode = mojom::MeteringMode::MANUAL;
99 }
100 }
101
102 return control_range;
103 }
104
65 // Finds and creates a DirectShow Video Capture filter matching the |device_id|. 105 // Finds and creates a DirectShow Video Capture filter matching the |device_id|.
66 // static 106 // static
67 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id, 107 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,
68 IBaseFilter** filter) { 108 IBaseFilter** filter) {
69 DCHECK(filter); 109 DCHECK(filter);
70 110
71 ScopedComPtr<ICreateDevEnum> dev_enum; 111 ScopedComPtr<ICreateDevEnum> dev_enum;
72 HRESULT hr = 112 HRESULT hr =
73 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC); 113 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC);
74 if (FAILED(hr)) 114 if (FAILED(hr))
(...skipping 11 matching lines...) Expand all
86 for (ScopedComPtr<IMoniker> moniker; 126 for (ScopedComPtr<IMoniker> moniker;
87 enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK; 127 enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK;
88 moniker.Reset()) { 128 moniker.Reset()) {
89 ScopedComPtr<IPropertyBag> prop_bag; 129 ScopedComPtr<IPropertyBag> prop_bag;
90 hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&prop_bag)); 130 hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&prop_bag));
91 if (FAILED(hr)) 131 if (FAILED(hr))
92 continue; 132 continue;
93 133
94 // Find |device_id| via DevicePath, Description or FriendlyName, whichever 134 // Find |device_id| via DevicePath, Description or FriendlyName, whichever
95 // is available first and is a VT_BSTR (i.e. String) type. 135 // is available first and is a VT_BSTR (i.e. String) type.
96 static const wchar_t* kPropertyNames[] = { 136 static const wchar_t* kPropertyNames[] = {L"DevicePath", L"Description",
97 L"DevicePath", L"Description", L"FriendlyName"}; 137 L"FriendlyName"};
98 138
99 ScopedVariant name; 139 ScopedVariant name;
100 for (const auto* property_name : kPropertyNames) { 140 for (const auto* property_name : kPropertyNames) {
101 prop_bag->Read(property_name, name.Receive(), 0); 141 prop_bag->Read(property_name, name.Receive(), 0);
102 if (name.type() == VT_BSTR) 142 if (name.type() == VT_BSTR)
103 break; 143 break;
104 } 144 }
105 145
106 if (name.type() == VT_BSTR) { 146 if (name.type() == VT_BSTR) {
107 const std::string device_path(base::SysWideToUTF8(V_BSTR(name.ptr()))); 147 const std::string device_path(base::SysWideToUTF8(V_BSTR(name.ptr())));
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 } 188 }
149 } 189 }
150 pin.Reset(); 190 pin.Reset();
151 } 191 }
152 192
153 DCHECK(!pin.Get()); 193 DCHECK(!pin.Get());
154 return pin; 194 return pin;
155 } 195 }
156 196
157 // static 197 // static
158 VideoPixelFormat 198 VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
159 VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
160 const GUID& sub_type) { 199 const GUID& sub_type) {
161 static struct { 200 static struct {
162 const GUID& sub_type; 201 const GUID& sub_type;
163 VideoPixelFormat format; 202 VideoPixelFormat format;
164 } const kMediaSubtypeToPixelFormatCorrespondence[] = { 203 } const kMediaSubtypeToPixelFormatCorrespondence[] = {
165 {kMediaSubTypeI420, PIXEL_FORMAT_I420}, 204 {kMediaSubTypeI420, PIXEL_FORMAT_I420},
166 {MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420}, 205 {MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420},
167 {MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24}, 206 {MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24},
168 {MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2}, 207 {MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2},
169 {MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG}, 208 {MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG},
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 485
447 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) { 486 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) {
448 DCHECK(thread_checker_.CalledOnValidThread()); 487 DCHECK(thread_checker_.CalledOnValidThread());
449 // DirectShow has other means of capturing still pictures, e.g. connecting a 488 // DirectShow has other means of capturing still pictures, e.g. connecting a
450 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This 489 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This
451 // way, however, is not widespread and proves too cumbersome, so we just grab 490 // way, however, is not widespread and proves too cumbersome, so we just grab
452 // the next captured frame instead. 491 // the next captured frame instead.
453 take_photo_callbacks_.push(std::move(callback)); 492 take_photo_callbacks_.push(std::move(callback));
454 } 493 }
455 494
495 void VideoCaptureDeviceWin::GetPhotoCapabilities(
496 GetPhotoCapabilitiesCallback callback) {
497 DCHECK(thread_checker_.CalledOnValidThread());
498
499 base::win::ScopedComPtr<IKsTopologyInfo> info;
500 HRESULT hr = capture_filter_.CopyTo(info.Receive());
501 if (FAILED(hr)) {
502 SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr);
503 return;
504 }
505
506 DWORD num_nodes = 0;
507 hr = info->get_NumNodes(&num_nodes);
508 if (FAILED(hr)) {
509 SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr);
510 return;
511 }
512
513 // Every UVC camera is expected to have a single ICameraControl and a single
514 // IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones.
515 GUID node_type;
516 base::win::ScopedComPtr<ICameraControl> camera_control;
517 for (size_t i = 0; i < num_nodes; i++) {
518 info->get_NodeType(i, &node_type);
519 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) {
520 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(camera_control.Receive()));
521 if (SUCCEEDED(hr))
522 break;
523 SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr);
524 return;
525 }
526 }
527 if (!camera_control)
528 return;
529 base::win::ScopedComPtr<IVideoProcAmp> video_control;
530 for (size_t i = 0; i < num_nodes; i++) {
531 info->get_NodeType(i, &node_type);
532 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) {
533 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(video_control.Receive()));
534 if (SUCCEEDED(hr))
535 break;
536 SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr);
537 return;
538 }
539 }
540 if (!video_control)
541 return;
542
543 auto photo_capabilities = mojom::PhotoCapabilities::New();
544
545 photo_capabilities->exposure_compensation = RetrieveControlRangeAndCurrent(
546 [camera_control](auto... args) {
547 return camera_control->getRange_Exposure(args...);
548 },
549 [camera_control](auto... args) {
550 return camera_control->get_Exposure(args...);
551 },
552 &photo_capabilities->supported_exposure_modes,
553 &photo_capabilities->current_exposure_mode);
554
555 photo_capabilities->color_temperature = RetrieveControlRangeAndCurrent(
556 [video_control](auto... args) {
557 return video_control->getRange_WhiteBalance(args...);
558 },
559 [video_control](auto... args) {
560 return video_control->get_WhiteBalance(args...);
561 },
562 &photo_capabilities->supported_white_balance_modes,
563 &photo_capabilities->current_white_balance_mode);
564
565 // Ignore the returned Focus control range and status.
566 RetrieveControlRangeAndCurrent(
567 [camera_control](auto... args) {
568 return camera_control->getRange_Focus(args...);
569 },
570 [camera_control](auto... args) {
571 return camera_control->get_Focus(args...);
572 },
573 &photo_capabilities->supported_focus_modes,
574 &photo_capabilities->current_focus_mode);
575
576 photo_capabilities->iso = mojom::Range::New();
577
578 photo_capabilities->brightness = RetrieveControlRangeAndCurrent(
579 [video_control](auto... args) {
580 return video_control->getRange_Brightness(args...);
581 },
582 [video_control](auto... args) {
583 return video_control->get_Brightness(args...);
584 });
585 photo_capabilities->contrast = RetrieveControlRangeAndCurrent(
586 [video_control](auto... args) {
587 return video_control->getRange_Contrast(args...);
588 },
589 [video_control](auto... args) {
590 return video_control->get_Contrast(args...);
591 });
592 photo_capabilities->saturation = RetrieveControlRangeAndCurrent(
593 [video_control](auto... args) {
594 return video_control->getRange_Saturation(args...);
595 },
596 [video_control](auto... args) {
597 return video_control->get_Saturation(args...);
598 });
599 photo_capabilities->sharpness = RetrieveControlRangeAndCurrent(
600 [video_control](auto... args) {
601 return video_control->getRange_Sharpness(args...);
602 },
603 [video_control](auto... args) {
604 return video_control->get_Sharpness(args...);
605 });
606
607 photo_capabilities->zoom = RetrieveControlRangeAndCurrent(
608 [camera_control](auto... args) {
609 return camera_control->getRange_Zoom(args...);
610 },
611 [camera_control](auto... args) {
612 return camera_control->get_Zoom(args...);
613 });
614
615 photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER;
616 photo_capabilities->height = mojom::Range::New();
617 photo_capabilities->width = mojom::Range::New();
618 photo_capabilities->torch = false;
619
620 callback.Run(std::move(photo_capabilities));
621 }
622
456 // Implements SinkFilterObserver::SinkFilterObserver. 623 // Implements SinkFilterObserver::SinkFilterObserver.
457 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer, 624 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer,
458 int length, 625 int length,
459 const VideoCaptureFormat& format, 626 const VideoCaptureFormat& format,
460 base::TimeDelta timestamp) { 627 base::TimeDelta timestamp) {
461 if (first_ref_time_.is_null()) 628 if (first_ref_time_.is_null())
462 first_ref_time_ = base::TimeTicks::Now(); 629 first_ref_time_ = base::TimeTicks::Now();
463 630
464 // There is a chance that the platform does not provide us with the timestamp, 631 // There is a chance that the platform does not provide us with the timestamp,
465 // in which case, we use reference time to calculate a timestamp. 632 // in which case, we use reference time to calculate a timestamp.
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 void VideoCaptureDeviceWin::SetErrorState( 757 void VideoCaptureDeviceWin::SetErrorState(
591 const tracked_objects::Location& from_here, 758 const tracked_objects::Location& from_here,
592 const std::string& reason, 759 const std::string& reason,
593 HRESULT hr) { 760 HRESULT hr) {
594 DCHECK(thread_checker_.CalledOnValidThread()); 761 DCHECK(thread_checker_.CalledOnValidThread());
595 DLOG_IF_FAILED_WITH_HRESULT(reason, hr); 762 DLOG_IF_FAILED_WITH_HRESULT(reason, hr);
596 state_ = kError; 763 state_ = kError;
597 client_->OnError(from_here, reason); 764 client_->OnError(from_here, reason);
598 } 765 }
599 } // namespace media 766 } // 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