blob: 0d10d0df70b7fe16d5bb77408e23e07c24f0d5b8 [file] [log] [blame]
/*
* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "hal/usb/metadata_handler.h"
#include <algorithm>
#include <cmath>
#include <limits>
#include <map>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include <base/no_destructor.h>
#include <chromeos-config/libcros_config/cros_config.h>
#include "cros-camera/common.h"
#include "cros-camera/utils/camera_config.h"
#include "hal/usb/quirks.h"
#include "hal/usb/stream_format.h"
#include "hal/usb/v4l2_camera_device.h"
#include "hal/usb/vendor_tag.h"
#include "mojo/cros_camera_enum.mojom.h"
namespace cros {
namespace {
constexpr int32_t kMinFps = 1;
constexpr float kDefaultAvailableFocalLength = 1.6f;
constexpr float kDefaultMinimumFocusDistance = 0.3f;
constexpr float kDefaultLensFocusDistance = 0.5f;
const cros::AwbModeToTemperatureMap& GetAwbModeTemperatureMap() {
// https://source.android.com/devices/camera/camera3_3Amodes#auto-wb
static const base::NoDestructor<cros::AwbModeToTemperatureMap>
kAwbModeTemperatureMap({
{ANDROID_CONTROL_AWB_MODE_INCANDESCENT, 2700},
{ANDROID_CONTROL_AWB_MODE_FLUORESCENT, 5000},
{ANDROID_CONTROL_AWB_MODE_WARM_FLUORESCENT, 3000},
{ANDROID_CONTROL_AWB_MODE_DAYLIGHT, 5500},
{ANDROID_CONTROL_AWB_MODE_CLOUDY_DAYLIGHT, 6500},
{ANDROID_CONTROL_AWB_MODE_TWILIGHT, 15000},
{ANDROID_CONTROL_AWB_MODE_SHADE, 7500},
});
return *kAwbModeTemperatureMap;
}
uint32_t GetAwbTemperatureByMode(
const cros::ControlRange& range,
camera_metadata_enum_android_control_awb_mode mode) {
const cros::AwbModeToTemperatureMap& map = GetAwbModeTemperatureMap();
if (mode == ANDROID_CONTROL_AWB_MODE_AUTO)
return 0;
auto it = map.find(mode);
if (it == map.end()) {
LOGF(ERROR) << "Can't find mode " << mode;
return 0;
}
// Get acceptable temperature by minimum and step. in case the step is
// too large.
uint32_t temperature =
range.minimum + range.step * ((it->second - range.minimum) / range.step);
if (temperature < range.minimum || temperature > range.maximum)
return 0;
return temperature;
}
std::vector<float> GetPhysicalSize(float horiz_fov,
float vert_fov,
float focal_length,
float array_aspect,
float still_aspect) {
float angle_to_rad_ratio = M_PI / 180.f;
float crop_factor = still_aspect / array_aspect;
float horiz_crop_factor = std::min(1.f, crop_factor);
float vert_crop_factor = std::min(1.f, 1.f / crop_factor);
return {2.f * focal_length * std::tan(horiz_fov * angle_to_rad_ratio / 2.f) /
horiz_crop_factor,
2.f * focal_length * std::tan(vert_fov * angle_to_rad_ratio / 2.f) /
vert_crop_factor};
}
// The unit of ANDROID_LENS_FOCUS_DISTANCE is diopters (1/meter), but the unit
// of V4L2_CID_FOCUS_ABSOLUTE is undefined. We map the V4L2 value to diopters by
// (value - minimum) / normalize_factor where |value| is in [minimum, maximum].
// We calculate a proper |normalize_factor| by assuming the minimum focus
// distance of USB cameras is >= 1cm (tested on real webcams), i.e. max diopter
// is <= 100, and only use power of 10s for readability.
// For example, V4L2 range [0, 250] will map to Android range [0, 25], where the
// minimum focus distance is 1m/25=4cm. This function takes |v4l2_range|
// (== maximum - minimum) and returns |normalize_factor|.
uint32_t GetNormalizeFactorForV4l2FocusRange(float v4l2_range) {
uint32_t normalize_factor = 1;
while (v4l2_range / normalize_factor > 100.0)
normalize_factor *= 10;
return normalize_factor;
}
class MetadataUpdater {
public:
explicit MetadataUpdater(android::CameraMetadata* metadata)
: metadata_(metadata), ok_(true) {}
bool ok() { return ok_; }
template <typename T>
void operator()(int tag, const std::vector<T>& data) {
if (!ok_) {
return;
}
if (metadata_->update(tag, data) != 0) {
ok_ = false;
LOGF(ERROR) << "Update metadata with tag " << std::hex << std::showbase
<< tag << " failed" << std::dec;
}
}
template <typename T>
std::enable_if_t<std::is_enum<T>::value> operator()(int tag, const T& data) {
static const std::set<int> kInt32EnumTags = {
ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS,
ANDROID_SCALER_AVAILABLE_FORMATS,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
ANDROID_SENSOR_TEST_PATTERN_MODE,
ANDROID_SYNC_MAX_LATENCY,
};
if (kInt32EnumTags.find(tag) != kInt32EnumTags.end()) {
operator()(tag, std::vector<int32_t>{static_cast<int32_t>(data)});
} else {
operator()(tag, std::vector<uint8_t>{base::checked_cast<uint8_t>(data)});
}
}
template <typename T>
std::enable_if_t<!std::is_enum<T>::value> operator()(int tag, const T& data) {
operator()(tag, std::vector<T>{data});
}
private:
android::CameraMetadata* metadata_;
bool ok_;
};
// Checks if a fps range can be filled into aeAvailableTargetFpsRanges given a
// list of supported formats.
// Android metadata only reports min frame duration for each format/resolution.
// CTS assumes a fps range is supported if the min frame duration (1/max_fps)
// covers the range. Thus we need to check if the USB camera actually supports
// some fps in the range.
bool IsFpsRangeSupported(const SupportedFormats& supported_formats,
int32_t fps_range_min,
int32_t fps_range_max) {
for (const auto& format : supported_formats) {
const int32_t max_fps = static_cast<int32_t>(*std::max_element(
format.frame_rates.begin(), format.frame_rates.end()));
if (max_fps >= fps_range_max) {
const bool has_fps_in_range = std::any_of(
format.frame_rates.begin(), format.frame_rates.end(), [&](float x) {
const int32_t fps = static_cast<int32_t>(x);
return fps_range_min <= fps && fps <= fps_range_max;
});
if (!has_fps_in_range)
return false;
}
}
return true;
}
Size GetMaxDimensions(const SupportedFormats& formats) {
uint32_t max_width = 0;
uint32_t max_height = 0;
for (const SupportedFormat& format : formats) {
max_width = std::max(max_width, format.width);
max_height = std::max(max_height, format.height);
}
return Size(max_width, max_height);
}
} // namespace
MetadataHandler::MetadataHandler(const camera_metadata_t& static_metadata,
const camera_metadata_t& request_template,
const DeviceInfo& device_info,
V4L2CameraDevice* device,
const SupportedFormats& supported_formats)
: device_info_(device_info),
device_(device),
af_trigger_(false),
focus_distance_normalize_factor_(0) {
// MetadataBase::operator= will make a copy of camera_metadata_t.
static_metadata_ = &static_metadata;
request_template_ = &request_template;
max_supported_fps_ = 0;
for (const auto& format : supported_formats) {
for (const float& frame_rate : format.frame_rates) {
// Since the |frame_rate| is a float, we need to round here.
int fps = std::round(frame_rate);
if (fps > max_supported_fps_) {
max_supported_fps_ = fps;
}
}
}
// camera3_request_template_t starts at 1.
for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
template_settings_[i] = CreateDefaultRequestSettings(i);
}
sensor_handler_ = SensorHandler::Create(device_info, supported_formats);
is_awb_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info_.device_path, kControlWhiteBalanceTemperature);
awb_temperature_ = GetAvailableAwbTemperatures(device_info);
is_brightness_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlBrightness);
is_contrast_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlContrast);
is_pan_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlPan);
is_saturation_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlSaturation);
is_sharpness_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlSharpness);
is_tilt_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlTilt);
is_zoom_control_supported_ = V4L2CameraDevice::IsControlSupported(
device_info.device_path, kControlZoom);
if (V4L2CameraDevice::IsFocusDistanceSupported(device_info.device_path,
&focus_distance_range_)) {
float full_range =
focus_distance_range_.maximum - focus_distance_range_.minimum;
focus_distance_normalize_factor_ =
GetNormalizeFactorForV4l2FocusRange(full_range);
}
thread_checker_.DetachFromThread();
}
MetadataHandler::~MetadataHandler() {}
int MetadataHandler::FillDefaultMetadata(
android::CameraMetadata* static_metadata,
android::CameraMetadata* request_metadata) {
MetadataUpdater update_static(static_metadata);
MetadataUpdater update_request(request_metadata);
// android.colorCorrection
update_static(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
std::vector<uint8_t>{
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST,
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY});
update_request(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_FAST);
// android.control
// We don't support AE compensation.
update_static(ANDROID_CONTROL_AE_COMPENSATION_RANGE,
std::vector<int32_t>{0, 0});
update_static(ANDROID_CONTROL_AE_COMPENSATION_STEP,
camera_metadata_rational_t{0, 1});
update_static(ANDROID_CONTROL_MAX_REGIONS,
std::vector<int32_t>{/*AE*/ 0, /*AWB*/ 0, /*AF*/ 0});
update_static(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF);
update_request(ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF);
update_static(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
ANDROID_CONTROL_AWB_MODE_AUTO);
update_request(ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_AWB_MODE_AUTO);
update_static(ANDROID_CONTROL_AE_AVAILABLE_MODES, ANDROID_CONTROL_AE_MODE_ON);
// ON means auto-exposure is active with no flash control.
update_request(ANDROID_CONTROL_AE_MODE, ANDROID_CONTROL_AE_MODE_ON);
update_request(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, int32_t{0});
update_request(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
update_request(ANDROID_CONTROL_AF_TRIGGER, ANDROID_CONTROL_AF_TRIGGER_IDLE);
update_static(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
ANDROID_CONTROL_SCENE_MODE_DISABLED);
update_request(ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_SCENE_MODE_DISABLED);
update_static(ANDROID_CONTROL_AVAILABLE_EFFECTS,
ANDROID_CONTROL_EFFECT_MODE_OFF);
update_request(ANDROID_CONTROL_EFFECT_MODE, ANDROID_CONTROL_EFFECT_MODE_OFF);
update_static(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE);
update_static(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE);
update_static(ANDROID_CONTROL_AVAILABLE_MODES,
std::vector<uint8_t>{ANDROID_CONTROL_MODE_OFF,
ANDROID_CONTROL_MODE_AUTO});
// android.flash
update_static(ANDROID_FLASH_INFO_AVAILABLE,
ANDROID_FLASH_INFO_AVAILABLE_FALSE);
update_request(ANDROID_FLASH_STATE, ANDROID_FLASH_STATE_UNAVAILABLE);
update_request(ANDROID_FLASH_MODE, ANDROID_FLASH_MODE_OFF);
// android.jpeg
update_static(ANDROID_JPEG_MAX_SIZE, int32_t{13 << 20});
update_request(ANDROID_JPEG_QUALITY, uint8_t{90});
update_request(ANDROID_JPEG_THUMBNAIL_QUALITY, uint8_t{90});
update_request(ANDROID_JPEG_ORIENTATION, int32_t{0});
// android.lens
// This should not be needed.
update_static(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE, 0.0f);
update_static(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF);
update_request(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF);
// android.noiseReduction
update_static(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
ANDROID_NOISE_REDUCTION_MODE_OFF);
update_request(ANDROID_NOISE_REDUCTION_MODE,
ANDROID_NOISE_REDUCTION_MODE_OFF);
// android.request
update_static(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
update_static(ANDROID_REQUEST_PARTIAL_RESULT_COUNT, int32_t{1});
// This means pipeline latency of X frame intervals. The maximum number is 4.
update_static(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, uint8_t{4});
update_request(ANDROID_REQUEST_PIPELINE_DEPTH, uint8_t{4});
// Three numbers represent the maximum numbers of different types of output
// streams simultaneously. The types are raw sensor, processed (but not
// stalling), and processed (but stalling). For usb limited mode, raw sensor
// is not supported. Stalling stream is JPEG. Non-stalling streams are
// YUV_420_888, NV21, or YV12.
update_static(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
std::vector<int32_t>{0, 2, 1});
// Limited mode doesn't support reprocessing.
update_static(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS, int32_t{0});
// android.scaler
update_static(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, 1.0f);
update_static(ANDROID_SCALER_CROPPING_TYPE,
ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY);
update_static(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
std::vector<int32_t>{
ANDROID_SENSOR_TEST_PATTERN_MODE_OFF,
ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY});
update_request(ANDROID_SENSOR_TEST_PATTERN_MODE,
ANDROID_SENSOR_TEST_PATTERN_MODE_OFF);
uint8_t timestamp_source;
if (V4L2CameraDevice::GetUvcClock() == CLOCK_BOOTTIME) {
timestamp_source = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_REALTIME;
} else {
timestamp_source = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
}
update_static(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, timestamp_source);
// android.shading
update_static(ANDROID_SHADING_AVAILABLE_MODES, ANDROID_SHADING_MODE_FAST);
// android.statistics
update_static(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
ANDROID_STATISTICS_FACE_DETECT_MODE_OFF);
update_request(ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_FACE_DETECT_MODE_OFF);
update_static(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT, int32_t{0});
update_static(ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF);
update_request(ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE_OFF);
update_static(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
// android.sync
update_static(ANDROID_SYNC_MAX_LATENCY, ANDROID_SYNC_MAX_LATENCY_UNKNOWN);
return update_static.ok() && update_request.ok() ? 0 : -EINVAL;
}
int MetadataHandler::FillMetadataFromSupportedFormats(
const SupportedFormats& supported_formats,
const DeviceInfo& device_info,
android::CameraMetadata* static_metadata,
android::CameraMetadata* request_metadata) {
bool is_external = device_info.lens_facing == LensFacing::kExternal;
bool is_builtin = !is_external;
bool is_v1_builtin = device_info.quirks & kQuirkV1Device;
if (supported_formats.empty()) {
return -EINVAL;
}
std::vector<int32_t> stream_configurations;
std::vector<int64_t> min_frame_durations;
std::vector<int64_t> stall_durations;
// The min fps <= 15 must be supported in CTS.
const int64_t kOneSecOfNanoUnit = 1000000000LL;
int32_t max_fps = std::numeric_limits<int32_t>::min();
int64_t max_frame_duration = kOneSecOfNanoUnit / kMinFps;
std::set<int32_t> supported_fps;
std::vector<int> hal_formats{HAL_PIXEL_FORMAT_BLOB,
HAL_PIXEL_FORMAT_YCbCr_420_888,
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED};
std::unordered_map<int, int> max_hal_width_by_format;
std::unordered_map<int, int> max_hal_height_by_format;
std::unique_ptr<CameraConfig> camera_config =
CameraConfig::Create(constants::kCrosCameraConfigPathString);
max_hal_width_by_format[HAL_PIXEL_FORMAT_BLOB] = camera_config->GetInteger(
constants::kCrosMaxBlobWidth, std::numeric_limits<int>::max());
max_hal_width_by_format[HAL_PIXEL_FORMAT_YCbCr_420_888] =
camera_config->GetInteger(constants::kCrosMaxYuvWidth,
std::numeric_limits<int>::max());
max_hal_width_by_format[HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED] =
camera_config->GetInteger(constants::kCrosMaxPrivateWidth,
std::numeric_limits<int>::max());
max_hal_height_by_format[HAL_PIXEL_FORMAT_BLOB] = camera_config->GetInteger(
constants::kCrosMaxBlobHeight, std::numeric_limits<int>::max());
max_hal_height_by_format[HAL_PIXEL_FORMAT_YCbCr_420_888] =
camera_config->GetInteger(constants::kCrosMaxYuvHeight,
std::numeric_limits<int>::max());
max_hal_height_by_format[HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED] =
camera_config->GetInteger(constants::kCrosMaxPrivateHeight,
std::numeric_limits<int>::max());
for (const auto& supported_format : supported_formats) {
int64_t min_frame_duration = std::numeric_limits<int64_t>::max();
int32_t per_format_max_fps = std::numeric_limits<int32_t>::min();
for (const auto& frame_rate : supported_format.frame_rates) {
// To prevent floating point precision problem we cast the floating point
// to double here.
int64_t frame_duration =
kOneSecOfNanoUnit / static_cast<double>(frame_rate);
if (frame_duration < min_frame_duration) {
min_frame_duration = frame_duration;
}
if (frame_duration > max_frame_duration) {
max_frame_duration = frame_duration;
}
if (per_format_max_fps < static_cast<int32_t>(frame_rate)) {
per_format_max_fps = static_cast<int32_t>(frame_rate);
}
supported_fps.insert(frame_rate);
}
if (per_format_max_fps > max_fps) {
max_fps = per_format_max_fps;
}
for (const auto& format : hal_formats) {
if (is_builtin) {
if (supported_format.width > max_hal_width_by_format[format]) {
LOGF(INFO) << "Filter Format: 0x" << std::hex << format << std::dec
<< "-width " << supported_format.width << ". max is "
<< max_hal_width_by_format[format];
continue;
}
if (supported_format.height > max_hal_height_by_format[format]) {
LOGF(INFO) << "Filter Format: 0x" << std::hex << format << std::dec
<< "-height " << supported_format.height << ". max is "
<< max_hal_height_by_format[format];
continue;
}
if (format != HAL_PIXEL_FORMAT_BLOB && per_format_max_fps < 30) {
continue;
}
}
stream_configurations.push_back(format);
stream_configurations.push_back(supported_format.width);
stream_configurations.push_back(supported_format.height);
stream_configurations.push_back(
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);
min_frame_durations.push_back(format);
min_frame_durations.push_back(supported_format.width);
min_frame_durations.push_back(supported_format.height);
min_frame_durations.push_back(min_frame_duration);
}
// The stall duration is 0 for non-jpeg formats. For JPEG format, stall
// duration can be 0 if JPEG is small. 5MP JPEG takes 700ms to decode
// and encode. Here we choose 1 sec for JPEG.
for (const auto& format : hal_formats) {
// For non-jpeg formats, the camera orientation workaround crops,
// rotates, and scales the frames. Theoretically the stall duration of
// huge resolution may be bigger than 0. Set it to 0 for now.
int64_t stall_duration =
(format == HAL_PIXEL_FORMAT_BLOB) ? 1000000000 : 0;
stall_durations.push_back(format);
stall_durations.push_back(supported_format.width);
stall_durations.push_back(supported_format.height);
stall_durations.push_back(stall_duration);
}
}
MetadataUpdater update_static(static_metadata);
MetadataUpdater update_request(request_metadata);
// The document in aeAvailableTargetFpsRanges section says the min fps should
// not be larger than 15.
// We enumerate all possible fps and put (min, fps) as available fps range. If
// the device support constant frame rate, put (fps, fps) into the list as
// well.
// TODO(wtlee): Handle non-integer fps when setting controls.
bool support_constant_framerate = !device_info.constant_framerate_unsupported;
std::vector<int32_t> available_fps_ranges;
// For devices that cannot actually meet the fps ranges they report, only
// report (min, max) and optional (max, max) if they support constant frame
// rate.
if (device_info.quirks & kQuirkReportLeastFpsRanges) {
available_fps_ranges.push_back(kMinFps);
available_fps_ranges.push_back(max_fps);
if (support_constant_framerate) {
available_fps_ranges.push_back(max_fps);
available_fps_ranges.push_back(max_fps);
}
} else {
for (auto fps : supported_fps) {
// The IsFpsRangeSupported() filter should only apply on built-in
// cameras, otherwise some webcams with fps combinations that cannot be
// represented in HALv3 API would stop working (b/171845790).
if (is_external || IsFpsRangeSupported(supported_formats, kMinFps, fps)) {
available_fps_ranges.push_back(kMinFps);
available_fps_ranges.push_back(fps);
}
if (support_constant_framerate &&
(is_external || IsFpsRangeSupported(supported_formats, fps, fps))) {
available_fps_ranges.push_back(fps);
available_fps_ranges.push_back(fps);
}
}
}
update_static(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
available_fps_ranges);
update_static(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
stream_configurations);
update_static(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,
min_frame_durations);
update_static(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, stall_durations);
std::vector<int32_t> jpeg_available_thumbnail_sizes =
GetJpegAvailableThumbnailSizes(supported_formats);
update_static(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
jpeg_available_thumbnail_sizes);
update_request(ANDROID_JPEG_THUMBNAIL_SIZE,
std::vector<int32_t>(jpeg_available_thumbnail_sizes.end() - 2,
jpeg_available_thumbnail_sizes.end()));
update_static(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION, max_frame_duration);
const Size max_dimensions = GetMaxDimensions(supported_formats);
std::vector<int32_t> active_array_size(4);
if (device_info.sensor_info_active_array_size.is_valid()) {
const Rect<int32_t>& rect = device_info.sensor_info_active_array_size;
if (rect.width() < max_dimensions.width ||
rect.height() < max_dimensions.height) {
LOGF(ERROR) << "Sensor active array size (" << rect.width() << "x"
<< rect.height()
<< ") is smaller than max supported format dimensions ("
<< max_dimensions.width << "x" << max_dimensions.height
<< ")";
return -EINVAL;
}
active_array_size[0] = rect.left;
active_array_size[1] = rect.top;
active_array_size[2] = rect.right;
active_array_size[3] = rect.bottom;
} else {
active_array_size[0] = 0;
active_array_size[1] = 0;
active_array_size[2] = static_cast<int32_t>(max_dimensions.width);
active_array_size[3] = static_cast<int32_t>(max_dimensions.height);
}
update_static(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
active_array_size);
update_static(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE, active_array_size);
if (is_v1_builtin) {
if (FillSensorInfo(device_info, static_metadata,
static_cast<int32_t>(max_dimensions.width),
static_cast<int32_t>(max_dimensions.height)) != 0) {
LOGF(ERROR) << "Failed to fill sensor info for v1 built-in camera";
return -EINVAL;
}
} else if (is_external) {
// It's a sensible value for external camera, since it's required on all
// devices per spec. For built-in camera, this would be filled in
// FillMetadataFromDeviceInfo() or FillSensorInfo() using the value from the
// configuration file.
//
// The official document for this field:
// https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SENSOR_INFO_PIXEL_ARRAY_SIZE
update_static(
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
std::vector<int32_t>{static_cast<int32_t>(max_dimensions.width),
static_cast<int32_t>(max_dimensions.height)});
}
return update_static.ok() && update_request.ok() ? 0 : -EINVAL;
}
// static
AwbModeToTemperatureMap MetadataHandler::GetAvailableAwbTemperatures(
const DeviceInfo& device_info) {
AwbModeToTemperatureMap available_awb_temperatures;
available_awb_temperatures[ANDROID_CONTROL_AWB_MODE_AUTO] =
kColorTemperatureAuto;
if (!V4L2CameraDevice::IsControlSupported(device_info.device_path,
kControlAutoWhiteBalance))
return available_awb_temperatures;
ControlInfo info;
if (V4L2CameraDevice::QueryControl(
device_info.device_path, kControlWhiteBalanceTemperature, &info) != 0)
return available_awb_temperatures;
for (auto& mode_temperature : GetAwbModeTemperatureMap()) {
uint32_t temperature =
GetAwbTemperatureByMode(info.range, mode_temperature.first);
if (!temperature)
continue;
available_awb_temperatures[mode_temperature.first] = temperature;
}
return available_awb_temperatures;
}
// static
int MetadataHandler::FillMetadataFromDeviceInfo(
const DeviceInfo& device_info,
android::CameraMetadata* static_metadata,
android::CameraMetadata* request_metadata) {
MetadataUpdater update_static(static_metadata);
MetadataUpdater update_request(request_metadata);
bool is_external = device_info.lens_facing == LensFacing::kExternal;
bool is_builtin = !is_external;
bool is_v1_builtin = device_info.quirks & kQuirkV1Device;
bool is_v3_builtin = is_builtin && !is_v1_builtin;
std::vector<int32_t> available_request_keys = {
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
ANDROID_CONTROL_AE_LOCK,
ANDROID_CONTROL_AE_MODE,
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
ANDROID_CONTROL_AF_MODE,
ANDROID_CONTROL_AF_TRIGGER,
ANDROID_CONTROL_AWB_LOCK,
ANDROID_CONTROL_AWB_MODE,
ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_EFFECT_MODE,
ANDROID_CONTROL_MODE,
ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
ANDROID_FLASH_MODE,
ANDROID_JPEG_ORIENTATION,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_THUMBNAIL_QUALITY,
ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_SCALER_CROP_REGION,
ANDROID_SENSOR_TEST_PATTERN_MODE,
ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
};
if (is_builtin) {
available_request_keys.insert(available_request_keys.end(),
{
ANDROID_LENS_APERTURE,
ANDROID_LENS_FOCAL_LENGTH,
ANDROID_LENS_FOCUS_DISTANCE,
});
}
// TODO(shik): All properties listed for capture requests can also be queried
// on the capture result, to determine the final values used for capture. We
// shuold build this list from |available_request_keys|.
// ref:
// https://developer.android.com/reference/android/hardware/camera2/CaptureResult
std::vector<int32_t> available_result_keys = {
ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_CONTROL_AE_ANTIBANDING_MODE,
ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,
ANDROID_CONTROL_AE_LOCK,
ANDROID_CONTROL_AE_MODE,
ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,
ANDROID_CONTROL_AE_STATE,
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
ANDROID_CONTROL_AF_MODE,
ANDROID_CONTROL_AF_STATE,
ANDROID_CONTROL_AF_TRIGGER,
ANDROID_CONTROL_AWB_LOCK,
ANDROID_CONTROL_AWB_MODE,
ANDROID_CONTROL_AWB_STATE,
ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_EFFECT_MODE,
ANDROID_CONTROL_MODE,
ANDROID_CONTROL_SCENE_MODE,
ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,
ANDROID_FLASH_MODE,
ANDROID_FLASH_STATE,
ANDROID_JPEG_ORIENTATION,
ANDROID_JPEG_QUALITY,
ANDROID_JPEG_THUMBNAIL_QUALITY,
ANDROID_JPEG_THUMBNAIL_SIZE,
ANDROID_LENS_OPTICAL_STABILIZATION_MODE,
ANDROID_LENS_STATE,
ANDROID_NOISE_REDUCTION_MODE,
ANDROID_REQUEST_PIPELINE_DEPTH,
ANDROID_SCALER_CROP_REGION,
ANDROID_SENSOR_EXPOSURE_TIME,
ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
ANDROID_SENSOR_TEST_PATTERN_MODE,
ANDROID_SENSOR_TIMESTAMP,
ANDROID_STATISTICS_FACE_DETECT_MODE,
ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
ANDROID_STATISTICS_SCENE_FLICKER,
};
if (is_builtin) {
available_result_keys.insert(available_result_keys.end(),
{
ANDROID_LENS_APERTURE,
ANDROID_LENS_FOCAL_LENGTH,
ANDROID_LENS_FOCUS_DISTANCE,
});
}
// TODO(shik): The HAL must not have any tags in its static info that are not
// listed either here or in the vendor tag list. Some request/result metadata
// entries are also presented in the static info now, and we should fix it.
// ref:
// https://android.googlesource.com/platform/system/media/+/a8cff157ff0ed02fa7e29438f4889a9933c37768/camera/docs/docs.html#16298
std::vector<int32_t> available_characteristics_keys = {
ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
ANDROID_CONTROL_AE_AVAILABLE_MODES,
ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,
ANDROID_CONTROL_AE_COMPENSATION_RANGE,
ANDROID_CONTROL_AE_COMPENSATION_STEP,
ANDROID_CONTROL_AE_LOCK_AVAILABLE,
ANDROID_CONTROL_AF_AVAILABLE_MODES,
ANDROID_CONTROL_AVAILABLE_EFFECTS,
ANDROID_CONTROL_AVAILABLE_MODES,
ANDROID_CONTROL_AVAILABLE_SCENE_MODES,
ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
ANDROID_CONTROL_AWB_AVAILABLE_MODES,
ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
ANDROID_CONTROL_MAX_REGIONS,
ANDROID_FLASH_INFO_AVAILABLE,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,
ANDROID_JPEG_MAX_SIZE,
ANDROID_LENS_FACING,
ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,
ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,
ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,
ANDROID_REQUEST_PARTIAL_RESULT_COUNT,
ANDROID_REQUEST_PIPELINE_MAX_DEPTH,
ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
ANDROID_SCALER_CROPPING_TYPE,
ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,
ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,
ANDROID_SENSOR_ORIENTATION,
ANDROID_SHADING_AVAILABLE_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES,
ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,
ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,
ANDROID_SYNC_MAX_LATENCY,
};
if (is_builtin) {
if (!device_info.lens_info_available_apertures.empty()) {
// This field is optional. Only list it if it presents in the
// configuration.
available_characteristics_keys.insert(
available_characteristics_keys.end(),
{
ANDROID_LENS_INFO_AVAILABLE_APERTURES,
});
}
available_characteristics_keys.insert(
available_characteristics_keys.end(),
{
ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
});
}
update_static(ANDROID_SENSOR_ORIENTATION, device_info.sensor_orientation);
update_static(ANDROID_LENS_FACING,
static_cast<uint8_t>(device_info.lens_facing));
if (is_v3_builtin) {
update_static(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED);
update_static(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
device_info.lens_info_available_apertures);
update_request(ANDROID_LENS_APERTURE,
device_info.lens_info_available_apertures[0]);
update_static(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
device_info.lens_info_available_focal_lengths);
update_request(ANDROID_LENS_FOCAL_LENGTH,
device_info.lens_info_available_focal_lengths[0]);
update_static(
ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
std::vector<float>{device_info.sensor_info_physical_size_width,
device_info.sensor_info_physical_size_height});
update_static(
ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
std::vector<int32_t>{device_info.sensor_info_pixel_array_size_width,
device_info.sensor_info_pixel_array_size_height});
} else if (is_v1_builtin) {
update_static(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
if (device_info.lens_info_available_apertures.size() > 0) {
update_static(ANDROID_LENS_INFO_AVAILABLE_APERTURES,
device_info.lens_info_available_apertures);
update_request(ANDROID_LENS_APERTURE,
device_info.lens_info_available_apertures[0]);
}
if (device_info.lens_info_available_focal_lengths.size() > 0) {
update_static(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
device_info.lens_info_available_focal_lengths);
update_request(ANDROID_LENS_FOCAL_LENGTH,
device_info.lens_info_available_focal_lengths[0]);
} else {
update_static(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,
kDefaultAvailableFocalLength);
update_request(ANDROID_LENS_FOCAL_LENGTH, kDefaultAvailableFocalLength);
}
if (device_info.sensor_info_pixel_array_size_width > 0 &&
device_info.sensor_info_pixel_array_size_height > 0) {
update_static(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
std::vector<int32_t>{
device_info.sensor_info_pixel_array_size_width,
device_info.sensor_info_pixel_array_size_height});
}
// For |sensor_info_physical_size|, fill them later with supported formats
// information.
} else {
update_static(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
}
update_static(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO);
update_request(ANDROID_CONTROL_AE_ANTIBANDING_MODE,
ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO);
// Set vendor tags for specified boards.
if (device_info.quirks & kQuirkMonocle) {
int32_t timestamp_sync =
static_cast<int32_t>(mojom::CameraSensorSyncTimestamp::NEAREST);
update_static(kVendorTagTimestampSync, timestamp_sync);
}
ControlInfo info;
if (V4L2CameraDevice::QueryControl(device_info.device_path,
kControlBrightness, &info) == 0) {
update_static(kVendorTagControlBrightnessRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path, kControlContrast,
&info) == 0) {
update_static(kVendorTagControlContrastRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path, kControlPan,
&info) == 0) {
update_static(kVendorTagControlPanRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path,
kControlSaturation, &info) == 0) {
update_static(kVendorTagControlSaturationRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path, kControlSharpness,
&info) == 0) {
update_static(kVendorTagControlSharpnessRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path, kControlTilt,
&info) == 0) {
update_static(kVendorTagControlTiltRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
if (V4L2CameraDevice::QueryControl(device_info.device_path, kControlZoom,
&info) == 0) {
update_static(kVendorTagControlZoomRange,
std::vector<int32_t>{info.range.minimum, info.range.maximum,
info.range.step});
}
std::vector<uint8_t> available_awb_modes;
for (auto const& it : GetAvailableAwbTemperatures(device_info))
available_awb_modes.push_back(it.first);
update_static(ANDROID_CONTROL_AWB_AVAILABLE_MODES, available_awb_modes);
// Check if device supports manual exposure control.
ControlRange range;
if (V4L2CameraDevice::IsManualExposureTimeSupported(device_info.device_path,
&range)) {
update_static(ANDROID_CONTROL_AE_AVAILABLE_MODES,
std::vector<uint8_t>{ANDROID_CONTROL_AE_MODE_OFF,
ANDROID_CONTROL_AE_MODE_ON});
// The unit of the range is 100 us.
update_static(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,
std::vector<int64_t>{
range.minimum * 100 * 1000 /* ns */,
range.maximum * 100 * 1000 /* ns */
});
// CtsCameraTestCases needs it. This control is only effective if
// android.control.aeMode is set to OFF.
update_request(
ANDROID_SENSOR_EXPOSURE_TIME,
static_cast<int64_t>(range.default_value) * 100 * 1000 /* ns */);
available_characteristics_keys.push_back(
ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE);
available_request_keys.push_back(ANDROID_SENSOR_EXPOSURE_TIME);
}
// The unit of V4L2 focus distance is undefined, so set it to uncalibrated.
update_static(ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION,
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED);
if (V4L2CameraDevice::IsControlSupported(device_info.device_path,
kControlFocusAuto)) {
update_static(ANDROID_CONTROL_AF_AVAILABLE_MODES,
std::vector<uint8_t>{ANDROID_CONTROL_AF_MODE_OFF,
ANDROID_CONTROL_AF_MODE_AUTO});
update_request(ANDROID_CONTROL_AF_MODE, ANDROID_CONTROL_AF_MODE_AUTO);
update_request(ANDROID_LENS_FOCUS_DISTANCE, 0.0f);
if (V4L2CameraDevice::IsFocusDistanceSupported(device_info.device_path,
&range)) {
float full_range = range.maximum - range.minimum;
uint32_t factor = GetNormalizeFactorForV4l2FocusRange(full_range);
update_static(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
full_range / factor);
} else {
if (device_info.lens_info_minimum_focus_distance > 0) {
update_static(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
1.0f / device_info.lens_info_minimum_focus_distance);
} else {
update_static(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,
1.0f / kDefaultMinimumFocusDistance);
}
}
} else {
update_static(ANDROID_CONTROL_AF_AVAILABLE_MODES,
ANDROID_CONTROL_AF_MODE_OFF);
update_request(ANDROID_CONTROL_AF_MODE, ANDROID_CONTROL_AF_MODE_OFF);
update_static(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE, 0.0f);
}
update_static(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
available_characteristics_keys);
update_static(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, available_request_keys);
update_static(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, available_result_keys);
return update_static.ok() && update_request.ok() ? 0 : -EINVAL;
}
int MetadataHandler::FillSensorInfo(const DeviceInfo& device_info,
android::CameraMetadata* metadata,
int32_t array_width,
int32_t array_height) {
MetadataUpdater update_static(metadata);
if (device_info.sensor_info_pixel_array_size_width <= 0 ||
device_info.sensor_info_pixel_array_size_height <= 0) {
update_static(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,
std::vector<int32_t>{array_width, array_height});
}
float focal_length = device_info.lens_info_available_focal_lengths.size() > 0
? device_info.lens_info_available_focal_lengths[0]
: kDefaultAvailableFocalLength;
float aspect_ratio = 1.f * array_width / array_height;
bool is_closer_to_16_9 = std::fabs(aspect_ratio - 16.f / 9.f) <
std::fabs(aspect_ratio - 4.f / 3.f);
bool has_fov_info_16_9 = device_info.horizontal_view_angle_16_9 > 0.f &&
device_info.vertical_view_angle_16_9 > 0.f;
bool has_fov_info_4_3 = device_info.horizontal_view_angle_4_3 > 0.f &&
device_info.vertical_view_angle_4_3 > 0.f;
// Use the FOV information (16:9 or 4:3) whose aspect ratio is closer to the
// ratio of sensor array size to calculate the sensor physical size.
if (has_fov_info_16_9 && (is_closer_to_16_9 || !has_fov_info_4_3)) {
update_static(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
GetPhysicalSize(device_info.horizontal_view_angle_16_9,
device_info.vertical_view_angle_16_9,
focal_length, aspect_ratio, 16.f / 9.f));
} else if (has_fov_info_4_3) {
update_static(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
GetPhysicalSize(device_info.horizontal_view_angle_4_3,
device_info.vertical_view_angle_4_3,
focal_length, aspect_ratio, 4.f / 3.f));
} else if (device_info.sensor_info_physical_size_width > 0.f &&
device_info.sensor_info_physical_size_height > 0.f) {
// Since the sensor physical size might be incorrect, only use these values
// when there are no view angle information.
update_static(
ANDROID_SENSOR_INFO_PHYSICAL_SIZE,
std::vector<float>{device_info.sensor_info_physical_size_width,
device_info.sensor_info_physical_size_height});
} else {
LOGF(ERROR)
<< "Neither sensor physical size nor view angle information is found";
return -EINVAL;
}
return update_static.ok() ? 0 : -EINVAL;
}
const camera_metadata_t* MetadataHandler::GetDefaultRequestSettings(
int template_type) {
if (!IsValidTemplateType(template_type)) {
LOGF(ERROR) << "Invalid template request type: " << template_type;
return nullptr;
}
return template_settings_[template_type].get();
}
bool MetadataHandler::ShouldEnableConstantFrameRate(
const android::CameraMetadata* metadata) const {
if (device_info_.constant_framerate_unsupported) {
return false;
}
// TODO(shik): Add a helper function to do the exists() and find() combo, so
// it's less likely to have typos in the tag name.
if (metadata->exists(ANDROID_CONTROL_AE_TARGET_FPS_RANGE)) {
camera_metadata_ro_entry entry =
metadata->find(ANDROID_CONTROL_AE_TARGET_FPS_RANGE);
if (entry.data.i32[0] == entry.data.i32[1]) {
return true;
}
}
if (metadata->exists(ANDROID_CONTROL_CAPTURE_INTENT)) {
camera_metadata_ro_entry entry =
metadata->find(ANDROID_CONTROL_CAPTURE_INTENT);
switch (entry.data.u8[0]) {
case ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD:
case ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT:
return true;
}
}
return false;
}
int MetadataHandler::PreHandleRequest(int frame_number,
const Size& resolution,
android::CameraMetadata* metadata) {
DCHECK(thread_checker_.CalledOnValidThread());
MetadataUpdater update_request(metadata);
if (!device_info_.constant_framerate_unsupported) {
bool enable = ShouldEnableConstantFrameRate(metadata);
if (device_->SetControlValue(kControlExposureAutoPriority,
enable ? 0 : 1) != 0) {
LOGF(WARNING) << "Failed to set constant frame rate to " << std::boolalpha
<< enable;
}
}
if (metadata->exists(ANDROID_CONTROL_AF_TRIGGER)) {
camera_metadata_entry entry = metadata->find(ANDROID_CONTROL_AF_TRIGGER);
if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
af_trigger_ = true;
} else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
af_trigger_ = false;
}
}
if (metadata->exists(ANDROID_CONTROL_AF_MODE)) {
camera_metadata_entry entry = metadata->find(ANDROID_CONTROL_AF_MODE);
if (entry.data.u8[0] == ANDROID_CONTROL_AF_MODE_OFF) {
if (metadata->exists(ANDROID_LENS_FOCUS_DISTANCE) &&
focus_distance_normalize_factor_ > 0) {
entry = metadata->find(ANDROID_LENS_FOCUS_DISTANCE);
int32_t distance =
static_cast<int32_t>(entry.data.f[0] *
focus_distance_normalize_factor_) +
focus_distance_range_.minimum;
distance = std::min(distance, focus_distance_range_.maximum);
device_->SetAutoFocus(false);
device_->SetFocusDistance(distance);
int32_t focus_distance;
device_->GetControlValue(kControlFocusDistance, &focus_distance);
float simulate_diopters =
static_cast<float>(focus_distance - focus_distance_range_.minimum) /
focus_distance_normalize_factor_;
update_request(ANDROID_LENS_FOCUS_DISTANCE, simulate_diopters);
} else {
device_->SetAutoFocus(false);
}
} else if (entry.data.u8[0] == ANDROID_CONTROL_AF_MODE_AUTO) {
device_->SetAutoFocus(true);
float diopters;
if (device_info_.lens_info_optimal_focus_distance > 0) {
diopters = 1.0 / device_info_.lens_info_optimal_focus_distance;
} else {
diopters = 1.0 / kDefaultLensFocusDistance;
}
update_request(ANDROID_LENS_FOCUS_DISTANCE, diopters);
}
}
if (is_awb_control_supported_ && metadata->exists(ANDROID_CONTROL_AWB_MODE)) {
camera_metadata_entry entry = metadata->find(ANDROID_CONTROL_AWB_MODE);
auto mode = static_cast<camera_metadata_enum_android_control_awb_mode>(
entry.data.u8[0]);
if (awb_temperature_.count(mode))
device_->SetColorTemperature(awb_temperature_[mode]);
else
LOGF(WARNING) << "Unsupported AWB mode:" << mode;
}
const int64_t rolling_shutter_skew =
sensor_handler_->GetRollingShutterSkew(resolution);
update_request(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW, rolling_shutter_skew);
if (metadata->exists(kVendorTagControlBrightness)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlBrightness);
device_->SetControlValue(kControlBrightness, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlContrast)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlContrast);
device_->SetControlValue(kControlContrast, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlPan)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlPan);
device_->SetControlValue(kControlPan, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlSaturation)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlSaturation);
device_->SetControlValue(kControlSaturation, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlSharpness)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlSharpness);
device_->SetControlValue(kControlSharpness, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlTilt)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlTilt);
device_->SetControlValue(kControlTilt, entry.data.i32[0]);
}
if (metadata->exists(kVendorTagControlZoom)) {
camera_metadata_entry entry = metadata->find(kVendorTagControlZoom);
device_->SetControlValue(kControlZoom, entry.data.i32[0]);
}
if (metadata->exists(ANDROID_CONTROL_AE_MODE)) {
camera_metadata_entry entry = metadata->find(ANDROID_CONTROL_AE_MODE);
int32_t exposure_time;
switch (entry.data.u8[0]) {
case ANDROID_CONTROL_AE_MODE_ON:
device_->SetExposureTimeHundredUs(kExposureTimeAuto);
update_request(ANDROID_SENSOR_EXPOSURE_TIME,
sensor_handler_->GetExposureTime(resolution));
break;
case ANDROID_CONTROL_AE_MODE_OFF:
if (metadata->exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
entry = metadata->find(ANDROID_SENSOR_EXPOSURE_TIME);
exposure_time =
static_cast<int32_t>(entry.data.i64[0] / (100 * 1000)); // ns
device_->SetExposureTimeHundredUs(exposure_time);
device_->GetControlValue(kControlExposureTime, &exposure_time);
update_request(
ANDROID_SENSOR_EXPOSURE_TIME,
base::strict_cast<int64_t>(exposure_time) * 100 * 1000); // ns
} else {
LOGF(WARNING) << "There is no ANDROID_SENSOR_EXPOSURE_TIME metadata";
}
break;
default:
LOGF(WARNING) << "Unsupport AE mode " << entry.data.u8[0];
break;
}
}
current_frame_number_ = frame_number;
return 0;
}
int MetadataHandler::PostHandleRequest(int frame_number,
int64_t timestamp,
android::CameraMetadata* metadata) {
DCHECK(thread_checker_.CalledOnValidThread());
if (current_frame_number_ != frame_number) {
LOGF(ERROR)
<< "Frame number mismatch in PreHandleRequest and PostHandleRequest";
return -EINVAL;
}
MetadataUpdater update_request(metadata);
// android.control
// For USB camera, we don't know the AE state. Set the state to converged to
// indicate the frame should be good to use. Then apps don't have to wait the
// AE state.
update_request(ANDROID_CONTROL_AE_STATE, ANDROID_CONTROL_AE_STATE_CONVERGED);
update_request(ANDROID_CONTROL_AE_LOCK, ANDROID_CONTROL_AE_LOCK_OFF);
// For USB camera, the USB camera handles everything and we don't have control
// over AF. We only simply fake the AF metadata based on the request
// received here.
uint8_t af_state;
if (af_trigger_) {
af_state = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
} else {
af_state = ANDROID_CONTROL_AF_STATE_INACTIVE;
}
update_request(ANDROID_CONTROL_AF_STATE, af_state);
// Set AWB state to converged to indicate the frame should be good to use.
update_request(ANDROID_CONTROL_AWB_STATE,
ANDROID_CONTROL_AWB_STATE_CONVERGED);
update_request(ANDROID_CONTROL_AWB_LOCK, ANDROID_CONTROL_AWB_LOCK_OFF);
camera_metadata_entry active_array_size =
static_metadata_.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
if (active_array_size.count == 0) {
LOGF(ERROR) << "Active array size is not found.";
return -EINVAL;
}
// android.lens
// Since android.lens.focalLength, android.lens.focusDistance and
// android.lens.aperture are all fixed. And we don't support
// android.lens.filterDensity so we can set the state to stationary.
update_request(ANDROID_LENS_STATE, ANDROID_LENS_STATE_STATIONARY);
// android.scaler
update_request(ANDROID_SCALER_CROP_REGION, std::vector<int32_t>{
active_array_size.data.i32[0],
active_array_size.data.i32[1],
active_array_size.data.i32[2],
active_array_size.data.i32[3],
});
// android.sensor
update_request(ANDROID_SENSOR_TIMESTAMP, timestamp);
// android.statistics
update_request(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,
ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);
update_request(ANDROID_STATISTICS_SCENE_FLICKER,
ANDROID_STATISTICS_SCENE_FLICKER_NONE);
int32_t value;
if (is_brightness_control_supported_ &&
device_->GetControlValue(kControlBrightness, &value) == 0)
update_request(kVendorTagControlBrightness, value);
if (is_contrast_control_supported_ &&
device_->GetControlValue(kControlContrast, &value) == 0)
update_request(kVendorTagControlContrast, value);
if (is_pan_control_supported_ &&
device_->GetControlValue(kControlPan, &value) == 0)
update_request(kVendorTagControlPan, value);
if (is_saturation_control_supported_ &&
device_->GetControlValue(kControlSaturation, &value) == 0)
update_request(kVendorTagControlSaturation, value);
if (is_sharpness_control_supported_ &&
device_->GetControlValue(kControlSharpness, &value) == 0)
update_request(kVendorTagControlSharpness, value);
if (is_tilt_control_supported_ &&
device_->GetControlValue(kControlTilt, &value) == 0)
update_request(kVendorTagControlTilt, value);
if (is_zoom_control_supported_ &&
device_->GetControlValue(kControlZoom, &value) == 0)
update_request(kVendorTagControlZoom, value);
if (metadata->exists(ANDROID_CONTROL_AWB_MODE)) {
update_request(ANDROID_CONTROL_AWB_MODE, ANDROID_CONTROL_AWB_MODE_AUTO);
if (is_awb_control_supported_ &&
device_->GetControlValue(kControlAutoWhiteBalance, &value) == 0) {
if (!value && // Not auto white balance.
device_->GetControlValue(kControlWhiteBalanceTemperature, &value) ==
0) {
for (auto& mode_temperature : awb_temperature_) {
if (value == mode_temperature.second) {
update_request(ANDROID_CONTROL_AWB_MODE, mode_temperature.first);
break;
}
}
}
}
}
return 0;
}
bool MetadataHandler::IsValidTemplateType(int template_type) {
return template_type > 0 && template_type < CAMERA3_TEMPLATE_COUNT;
}
ScopedCameraMetadata MetadataHandler::CreateDefaultRequestSettings(
int template_type) {
android::CameraMetadata data(request_template_);
int ret;
switch (template_type) {
case CAMERA3_TEMPLATE_PREVIEW:
ret = FillDefaultPreviewSettings(&data);
break;
case CAMERA3_TEMPLATE_STILL_CAPTURE:
ret = FillDefaultStillCaptureSettings(&data);
break;
case CAMERA3_TEMPLATE_VIDEO_RECORD:
ret = FillDefaultVideoRecordSettings(&data);
break;
case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:
ret = FillDefaultVideoSnapshotSettings(&data);
break;
case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:
ret = FillDefaultZeroShutterLagSettings(&data);
break;
case CAMERA3_TEMPLATE_MANUAL:
ret = FillDefaultManualSettings(&data);
break;
default:
LOGF(ERROR) << "Invalid template request type: " << template_type;
return NULL;
}
if (ret) {
return ScopedCameraMetadata();
}
return ScopedCameraMetadata(data.release());
}
int MetadataHandler::FillDefaultPreviewSettings(
android::CameraMetadata* metadata) {
MetadataUpdater update_request(metadata);
// android.control
update_request(ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW);
update_request(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{kMinFps, max_supported_fps_});
update_request(ANDROID_CONTROL_MODE, ANDROID_CONTROL_MODE_AUTO);
// android.jpeg
update_request(ANDROID_JPEG_THUMBNAIL_SIZE, std::vector<int32_t>{0, 0});
return 0;
}
int MetadataHandler::FillDefaultStillCaptureSettings(
android::CameraMetadata* metadata) {
MetadataUpdater update_request(metadata);
// android.colorCorrection
update_request(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
ANDROID_COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
// android.control
update_request(ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
update_request(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{kMinFps, max_supported_fps_});
update_request(ANDROID_CONTROL_MODE, ANDROID_CONTROL_MODE_AUTO);
return 0;
}
int MetadataHandler::FillDefaultVideoRecordSettings(
android::CameraMetadata* metadata) {
MetadataUpdater update_request(metadata);
// android.control
update_request(ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD);
if (device_info_.constant_framerate_unsupported) {
update_request(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{kMinFps, max_supported_fps_});
} else {
update_request(
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{max_supported_fps_, max_supported_fps_});
}
update_request(ANDROID_CONTROL_MODE, ANDROID_CONTROL_MODE_AUTO);
return 0;
}
int MetadataHandler::FillDefaultVideoSnapshotSettings(
android::CameraMetadata* metadata) {
MetadataUpdater update_request(metadata);
// android.control
update_request(ANDROID_CONTROL_CAPTURE_INTENT,
ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT);
if (device_info_.constant_framerate_unsupported) {
update_request(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{kMinFps, max_supported_fps_});
} else {
update_request(
ANDROID_CONTROL_AE_TARGET_FPS_RANGE,
std::vector<int32_t>{max_supported_fps_, max_supported_fps_});
}
update_request(ANDROID_CONTROL_MODE, ANDROID_CONTROL_MODE_AUTO);
return 0;
}
int MetadataHandler::FillDefaultZeroShutterLagSettings(
android::CameraMetadata* /*metadata*/) {
// Do not support ZSL template.
return -EINVAL;
}
int MetadataHandler::FillDefaultManualSettings(
android::CameraMetadata* /*metadata*/) {
// Do not support manual template.
return -EINVAL;
}
} // namespace cros