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

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

Issue 2856893003: Image Capture: wire getCapabilities() in Windows (Closed)
Patch Set: 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,
robliao 2017/05/03 21:38:26 You can use the default = nullptr argument to save
mcasas 2017/05/03 22:16:49 Done.
73 mojom::MeteringMode* current_mode) {
74 auto control_range = mojom::Range::New();
robliao 2017/05/03 21:38:27 Will the caller be okay with any failure below?
mcasas 2017/05/03 22:16:49 Yes, returning an empty mojom::RangePtr is fine.
75 long min, max, step, default_value, flags, current;
76 HRESULT hr = range_getter(&min, &max, &step, &default_value, &flags);
77 DLOG_IF_FAILED_WITH_HRESULT("Control range reading failed", hr);
78 if (!FAILED(hr)) {
robliao 2017/05/03 21:38:26 Use SUCCEEDED(hr) here and below.
mcasas 2017/05/03 22:16:49 Done.
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 hr = value_getter(&current, &flags);
90 DLOG_IF_FAILED_WITH_HRESULT("Control value reading failed", hr);
91 if (!FAILED(hr)) {
92 control_range->current = current;
93 if (current_mode != nullptr) {
94 if (flags && CameraControl_Flags_Auto)
95 *current_mode = mojom::MeteringMode::CONTINUOUS;
96 else if (flags && CameraControl_Flags_Manual)
97 *current_mode = mojom::MeteringMode::MANUAL;
98 }
99 }
100
101 return control_range;
102 }
103
65 // Finds and creates a DirectShow Video Capture filter matching the |device_id|. 104 // Finds and creates a DirectShow Video Capture filter matching the |device_id|.
66 // static 105 // static
67 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id, 106 HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,
68 IBaseFilter** filter) { 107 IBaseFilter** filter) {
69 DCHECK(filter); 108 DCHECK(filter);
70 109
71 ScopedComPtr<ICreateDevEnum> dev_enum; 110 ScopedComPtr<ICreateDevEnum> dev_enum;
72 HRESULT hr = 111 HRESULT hr =
73 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC); 112 dev_enum.CreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC);
74 if (FAILED(hr)) 113 if (FAILED(hr))
(...skipping 11 matching lines...) Expand all
86 for (ScopedComPtr<IMoniker> moniker; 125 for (ScopedComPtr<IMoniker> moniker;
87 enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK; 126 enum_moniker->Next(1, moniker.Receive(), NULL) == S_OK;
88 moniker.Reset()) { 127 moniker.Reset()) {
89 ScopedComPtr<IPropertyBag> prop_bag; 128 ScopedComPtr<IPropertyBag> prop_bag;
90 hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&prop_bag)); 129 hr = moniker->BindToStorage(0, 0, IID_PPV_ARGS(&prop_bag));
91 if (FAILED(hr)) 130 if (FAILED(hr))
92 continue; 131 continue;
93 132
94 // Find |device_id| via DevicePath, Description or FriendlyName, whichever 133 // Find |device_id| via DevicePath, Description or FriendlyName, whichever
95 // is available first and is a VT_BSTR (i.e. String) type. 134 // is available first and is a VT_BSTR (i.e. String) type.
96 static const wchar_t* kPropertyNames[] = { 135 static const wchar_t* kPropertyNames[] = {L"DevicePath", L"Description",
97 L"DevicePath", L"Description", L"FriendlyName"}; 136 L"FriendlyName"};
98 137
99 ScopedVariant name; 138 ScopedVariant name;
100 for (const auto* property_name : kPropertyNames) { 139 for (const auto* property_name : kPropertyNames) {
101 prop_bag->Read(property_name, name.Receive(), 0); 140 prop_bag->Read(property_name, name.Receive(), 0);
102 if (name.type() == VT_BSTR) 141 if (name.type() == VT_BSTR)
103 break; 142 break;
104 } 143 }
105 144
106 if (name.type() == VT_BSTR) { 145 if (name.type() == VT_BSTR) {
107 const std::string device_path(base::SysWideToUTF8(V_BSTR(name.ptr()))); 146 const std::string device_path(base::SysWideToUTF8(V_BSTR(name.ptr())));
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 } 187 }
149 } 188 }
150 pin.Reset(); 189 pin.Reset();
151 } 190 }
152 191
153 DCHECK(!pin.Get()); 192 DCHECK(!pin.Get());
154 return pin; 193 return pin;
155 } 194 }
156 195
157 // static 196 // static
158 VideoPixelFormat 197 VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
159 VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
160 const GUID& sub_type) { 198 const GUID& sub_type) {
161 static struct { 199 static struct {
162 const GUID& sub_type; 200 const GUID& sub_type;
163 VideoPixelFormat format; 201 VideoPixelFormat format;
164 } const kMediaSubtypeToPixelFormatCorrespondence[] = { 202 } const kMediaSubtypeToPixelFormatCorrespondence[] = {
165 {kMediaSubTypeI420, PIXEL_FORMAT_I420}, 203 {kMediaSubTypeI420, PIXEL_FORMAT_I420},
166 {MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420}, 204 {MEDIASUBTYPE_IYUV, PIXEL_FORMAT_I420},
167 {MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24}, 205 {MEDIASUBTYPE_RGB24, PIXEL_FORMAT_RGB24},
168 {MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2}, 206 {MEDIASUBTYPE_YUY2, PIXEL_FORMAT_YUY2},
169 {MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG}, 207 {MEDIASUBTYPE_MJPG, PIXEL_FORMAT_MJPEG},
(...skipping 276 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 484
447 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) { 485 void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) {
448 DCHECK(thread_checker_.CalledOnValidThread()); 486 DCHECK(thread_checker_.CalledOnValidThread());
449 // DirectShow has other means of capturing still pictures, e.g. connecting a 487 // DirectShow has other means of capturing still pictures, e.g. connecting a
450 // SampleGrabber filter to a PIN_CATEGORY_STILL of |capture_filter_|. This 488 // 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 489 // way, however, is not widespread and proves too cumbersome, so we just grab
452 // the next captured frame instead. 490 // the next captured frame instead.
453 take_photo_callbacks_.push(std::move(callback)); 491 take_photo_callbacks_.push(std::move(callback));
454 } 492 }
455 493
494 void VideoCaptureDeviceWin::GetPhotoCapabilities(
495 GetPhotoCapabilitiesCallback callback) {
496 DCHECK(thread_checker_.CalledOnValidThread());
497
498 base::win::ScopedComPtr<IKsTopologyInfo> info;
499 HRESULT hr = capture_filter_.QueryInterface(info.Receive());
500 if (FAILED(hr)) {
501 SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr);
502 return;
503 }
504
505 DWORD num_nodes = 0;
506 hr = info->get_NumNodes(&num_nodes);
507 if (FAILED(hr)) {
508 SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr);
509 return;
510 }
511
512 GUID node_type;
513 base::win::ScopedComPtr<ICameraControl> camera_control;
514 base::win::ScopedComPtr<IVideoProcAmp> video_control;
515 for (size_t i = 0; i < num_nodes; i++) {
516 info->get_NodeType(i, &node_type);
517 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) {
518 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(camera_control.Receive()));
robliao 2017/05/03 21:38:26 Is it possible for the node list to have two types
mcasas 2017/05/03 22:16:49 Yes, as a matter of fact it's the usual and expect
robliao 2017/05/04 21:34:35 In that case, you might want to clear camera_contr
519 if (FAILED(hr)) {
520 SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr);
521 return;
522 }
523 }
524 if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) {
525 hr = info->CreateNodeInstance(i, IID_PPV_ARGS(video_control.Receive()));
526 if (FAILED(hr)) {
527 SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr);
528 return;
529 }
530 }
531 }
532 if (!camera_control || !video_control)
533 return;
534
535 auto photo_capabilities = mojom::PhotoCapabilities::New();
536
537 photo_capabilities->exposure_compensation = RetrieveControlRangeAndCurrent(
538 [camera_control](auto... args) {
robliao 2017/05/03 21:38:26 Optional: It might be better to just do the long*,
mcasas 2017/05/03 22:16:49 Correct, but if the calls in l.76 and l.89 would h
robliao 2017/05/04 21:34:35 Well, it would error out anyways in a failure to s
539 return camera_control->getRange_Exposure(args...);
540 },
541 [camera_control](auto... args) {
542 return camera_control->get_Exposure(args...);
543 },
544 &photo_capabilities->supported_exposure_modes,
545 &photo_capabilities->current_exposure_mode);
546
547 photo_capabilities->color_temperature = RetrieveControlRangeAndCurrent(
548 [video_control](auto... args) {
549 return video_control->getRange_WhiteBalance(args...);
550 },
551 [video_control](auto... args) {
552 return video_control->get_WhiteBalance(args...);
553 },
554 &photo_capabilities->supported_white_balance_modes,
555 &photo_capabilities->current_white_balance_mode);
556
557 // Ignore the returned Focus control range and status.
558 RetrieveControlRangeAndCurrent(
559 [camera_control](auto... args) {
560 return camera_control->getRange_Focus(args...);
561 },
562 [camera_control](auto... args) {
563 return camera_control->get_Focus(args...);
564 },
565 &photo_capabilities->supported_focus_modes,
566 &photo_capabilities->current_focus_mode);
567
568 photo_capabilities->iso = mojom::Range::New();
569
570 photo_capabilities->brightness = RetrieveControlRangeAndCurrent(
571 [video_control](auto... args) {
572 return video_control->getRange_Brightness(args...);
573 },
574 [video_control](auto... args) {
575 return video_control->get_Brightness(args...);
576 },
577 nullptr, nullptr);
578 photo_capabilities->contrast = RetrieveControlRangeAndCurrent(
579 [video_control](auto... args) {
580 return video_control->getRange_Contrast(args...);
581 },
582 [video_control](auto... args) {
583 return video_control->get_Contrast(args...);
584 },
585 nullptr, nullptr);
586 photo_capabilities->saturation = RetrieveControlRangeAndCurrent(
587 [video_control](auto... args) {
588 return video_control->getRange_Saturation(args...);
589 },
590 [video_control](auto... args) {
591 return video_control->get_Saturation(args...);
592 },
593 nullptr, nullptr);
594 photo_capabilities->sharpness = RetrieveControlRangeAndCurrent(
595 [video_control](auto... args) {
596 return video_control->getRange_Sharpness(args...);
597 },
598 [video_control](auto... args) {
599 return video_control->get_Sharpness(args...);
600 },
601 nullptr, nullptr);
602
603 photo_capabilities->zoom = RetrieveControlRangeAndCurrent(
604 [camera_control](auto... args) {
605 return camera_control->getRange_Zoom(args...);
606 },
607 [camera_control](auto... args) {
608 return camera_control->get_Zoom(args...);
609 },
610 nullptr, nullptr);
611
612 photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER;
613 photo_capabilities->height = mojom::Range::New();
614 photo_capabilities->width = mojom::Range::New();
615 photo_capabilities->torch = false;
616
617 callback.Run(std::move(photo_capabilities));
618 }
619
456 // Implements SinkFilterObserver::SinkFilterObserver. 620 // Implements SinkFilterObserver::SinkFilterObserver.
457 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer, 621 void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer,
458 int length, 622 int length,
459 const VideoCaptureFormat& format, 623 const VideoCaptureFormat& format,
460 base::TimeDelta timestamp) { 624 base::TimeDelta timestamp) {
461 if (first_ref_time_.is_null()) 625 if (first_ref_time_.is_null())
462 first_ref_time_ = base::TimeTicks::Now(); 626 first_ref_time_ = base::TimeTicks::Now();
463 627
464 // There is a chance that the platform does not provide us with the timestamp, 628 // 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. 629 // 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( 754 void VideoCaptureDeviceWin::SetErrorState(
591 const tracked_objects::Location& from_here, 755 const tracked_objects::Location& from_here,
592 const std::string& reason, 756 const std::string& reason,
593 HRESULT hr) { 757 HRESULT hr) {
594 DCHECK(thread_checker_.CalledOnValidThread()); 758 DCHECK(thread_checker_.CalledOnValidThread());
595 DLOG_IF_FAILED_WITH_HRESULT(reason, hr); 759 DLOG_IF_FAILED_WITH_HRESULT(reason, hr);
596 state_ = kError; 760 state_ = kError;
597 client_->OnError(from_here, reason); 761 client_->OnError(from_here, reason);
598 } 762 }
599 } // namespace media 763 } // 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