Skip to content

Commit

Permalink
Image Capture: wire getCapabilities() in Windows
Browse files Browse the repository at this point in the history
This CL implements the GetPhotoCapabilities() method for
Windows capture devices, by querying the appropriate
ICameraControl- and IVideoProcAmp-supporting nodes of the
|capture_filter_|.

Screenshots of the produced results vs the AmCap provided
values:
https://ibb.co/cfhCwQ
https://ibb.co/jNugqk
https://ibb.co/feiwO5
https://ibb.co/kShZAk

BUG=657128

Review-Url: https://codereview.chromium.org/2856893003
Cr-Commit-Position: refs/heads/master@{#469879}
  • Loading branch information
yell0wd0g authored and Commit bot committed May 6, 2017
1 parent 41b1693 commit 4461e2b
Show file tree
Hide file tree
Showing 2 changed files with 176 additions and 8 deletions.
183 changes: 175 additions & 8 deletions media/capture/video/win/video_capture_device_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <ks.h>
#include <ksmedia.h>
#include <objbase.h>
#include <vidcap.h>

#include <algorithm>
#include <list>
Expand All @@ -26,10 +27,10 @@ using base::win::ScopedVariant;
namespace media {

#if DCHECK_IS_ON()
#define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \
{ \
DLOG_IF(ERROR, FAILED(hr)) << (message) << ": " \
<< logging::SystemErrorCodeToString(hr); \
#define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \
{ \
DLOG_IF(ERROR, FAILED(hr)) \
<< (message) << ": " << logging::SystemErrorCodeToString(hr); \
}
#else
#define DLOG_IF_FAILED_WITH_HRESULT(message, hr) \
Expand Down Expand Up @@ -62,6 +63,45 @@ bool PinMatchesMajorType(IPin* pin, REFGUID major_type) {
return SUCCEEDED(hr) && connection_media_type.majortype == major_type;
}

// Retrieves the control range and value using the provided getters, and
// optionally returns the associated supported and current mode.
template <typename RangeGetter, typename ValueGetter>
mojom::RangePtr RetrieveControlRangeAndCurrent(
RangeGetter range_getter,
ValueGetter value_getter,
std::vector<mojom::MeteringMode>* supported_modes = nullptr,
mojom::MeteringMode* current_mode = nullptr) {
auto control_range = mojom::Range::New();
long min, max, step, default_value, flags;
HRESULT hr = range_getter(&min, &max, &step, &default_value, &flags);
DLOG_IF_FAILED_WITH_HRESULT("Control range reading failed", hr);
if (SUCCEEDED(hr)) {
control_range->min = min;
control_range->max = max;
control_range->step = step;
if (supported_modes != nullptr) {
if (flags && CameraControl_Flags_Auto)
supported_modes->push_back(mojom::MeteringMode::CONTINUOUS);
if (flags && CameraControl_Flags_Manual)
supported_modes->push_back(mojom::MeteringMode::MANUAL);
}
}
long current;
hr = value_getter(&current, &flags);
DLOG_IF_FAILED_WITH_HRESULT("Control value reading failed", hr);
if (SUCCEEDED(hr)) {
control_range->current = current;
if (current_mode != nullptr) {
if (flags && CameraControl_Flags_Auto)
*current_mode = mojom::MeteringMode::CONTINUOUS;
else if (flags && CameraControl_Flags_Manual)
*current_mode = mojom::MeteringMode::MANUAL;
}
}

return control_range;
}

// Finds and creates a DirectShow Video Capture filter matching the |device_id|.
// static
HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,
Expand Down Expand Up @@ -93,8 +133,8 @@ HRESULT VideoCaptureDeviceWin::GetDeviceFilter(const std::string& device_id,

// Find |device_id| via DevicePath, Description or FriendlyName, whichever
// is available first and is a VT_BSTR (i.e. String) type.
static const wchar_t* kPropertyNames[] = {
L"DevicePath", L"Description", L"FriendlyName"};
static const wchar_t* kPropertyNames[] = {L"DevicePath", L"Description",
L"FriendlyName"};

ScopedVariant name;
for (const auto* property_name : kPropertyNames) {
Expand Down Expand Up @@ -155,8 +195,7 @@ ScopedComPtr<IPin> VideoCaptureDeviceWin::GetPin(IBaseFilter* filter,
}

// static
VideoPixelFormat
VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
VideoPixelFormat VideoCaptureDeviceWin::TranslateMediaSubtypeToPixelFormat(
const GUID& sub_type) {
static struct {
const GUID& sub_type;
Expand Down Expand Up @@ -453,6 +492,134 @@ void VideoCaptureDeviceWin::TakePhoto(TakePhotoCallback callback) {
take_photo_callbacks_.push(std::move(callback));
}

void VideoCaptureDeviceWin::GetPhotoCapabilities(
GetPhotoCapabilitiesCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());

base::win::ScopedComPtr<IKsTopologyInfo> info;
HRESULT hr = capture_filter_.CopyTo(info.Receive());
if (FAILED(hr)) {
SetErrorState(FROM_HERE, "Failed to obtain the topology info.", hr);
return;
}

DWORD num_nodes = 0;
hr = info->get_NumNodes(&num_nodes);
if (FAILED(hr)) {
SetErrorState(FROM_HERE, "Failed to obtain the number of nodes.", hr);
return;
}

// Every UVC camera is expected to have a single ICameraControl and a single
// IVideoProcAmp nodes, and both are needed; ignore any unlikely later ones.
GUID node_type;
base::win::ScopedComPtr<ICameraControl> camera_control;
for (size_t i = 0; i < num_nodes; i++) {
info->get_NodeType(i, &node_type);
if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_CAMERA_TERMINAL)) {
hr = info->CreateNodeInstance(i, IID_PPV_ARGS(camera_control.Receive()));
if (SUCCEEDED(hr))
break;
SetErrorState(FROM_HERE, "Failed to retrieve the ICameraControl.", hr);
return;
}
}
if (!camera_control)
return;
base::win::ScopedComPtr<IVideoProcAmp> video_control;
for (size_t i = 0; i < num_nodes; i++) {
info->get_NodeType(i, &node_type);
if (IsEqualGUID(node_type, KSNODETYPE_VIDEO_PROCESSING)) {
hr = info->CreateNodeInstance(i, IID_PPV_ARGS(video_control.Receive()));
if (SUCCEEDED(hr))
break;
SetErrorState(FROM_HERE, "Failed to retrieve the IVideoProcAmp.", hr);
return;
}
}
if (!video_control)
return;

auto photo_capabilities = mojom::PhotoCapabilities::New();

photo_capabilities->exposure_compensation = RetrieveControlRangeAndCurrent(
[camera_control](auto... args) {
return camera_control->getRange_Exposure(args...);
},
[camera_control](auto... args) {
return camera_control->get_Exposure(args...);
},
&photo_capabilities->supported_exposure_modes,
&photo_capabilities->current_exposure_mode);

photo_capabilities->color_temperature = RetrieveControlRangeAndCurrent(
[video_control](auto... args) {
return video_control->getRange_WhiteBalance(args...);
},
[video_control](auto... args) {
return video_control->get_WhiteBalance(args...);
},
&photo_capabilities->supported_white_balance_modes,
&photo_capabilities->current_white_balance_mode);

// Ignore the returned Focus control range and status.
RetrieveControlRangeAndCurrent(
[camera_control](auto... args) {
return camera_control->getRange_Focus(args...);
},
[camera_control](auto... args) {
return camera_control->get_Focus(args...);
},
&photo_capabilities->supported_focus_modes,
&photo_capabilities->current_focus_mode);

photo_capabilities->iso = mojom::Range::New();

photo_capabilities->brightness = RetrieveControlRangeAndCurrent(
[video_control](auto... args) {
return video_control->getRange_Brightness(args...);
},
[video_control](auto... args) {
return video_control->get_Brightness(args...);
});
photo_capabilities->contrast = RetrieveControlRangeAndCurrent(
[video_control](auto... args) {
return video_control->getRange_Contrast(args...);
},
[video_control](auto... args) {
return video_control->get_Contrast(args...);
});
photo_capabilities->saturation = RetrieveControlRangeAndCurrent(
[video_control](auto... args) {
return video_control->getRange_Saturation(args...);
},
[video_control](auto... args) {
return video_control->get_Saturation(args...);
});
photo_capabilities->sharpness = RetrieveControlRangeAndCurrent(
[video_control](auto... args) {
return video_control->getRange_Sharpness(args...);
},
[video_control](auto... args) {
return video_control->get_Sharpness(args...);
});

photo_capabilities->zoom = RetrieveControlRangeAndCurrent(
[camera_control](auto... args) {
return camera_control->getRange_Zoom(args...);
},
[camera_control](auto... args) {
return camera_control->get_Zoom(args...);
});

photo_capabilities->red_eye_reduction = mojom::RedEyeReduction::NEVER;
photo_capabilities->height = mojom::Range::New();
photo_capabilities->width = mojom::Range::New();
photo_capabilities->torch = false;

callback.Run(std::move(photo_capabilities));
}

// Implements SinkFilterObserver::SinkFilterObserver.
void VideoCaptureDeviceWin::FrameReceived(const uint8_t* buffer,
int length,
Expand Down
1 change: 1 addition & 0 deletions media/capture/video/win/video_capture_device_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class VideoCaptureDeviceWin : public VideoCaptureDevice,
std::unique_ptr<VideoCaptureDevice::Client> client) override;
void StopAndDeAllocate() override;
void TakePhoto(TakePhotoCallback callback) override;
void GetPhotoCapabilities(GetPhotoCapabilitiesCallback callback) override;

private:
enum InternalState {
Expand Down

0 comments on commit 4461e2b

Please sign in to comment.