You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
16 KiB
402 lines
16 KiB
/*
|
|
* Copyright (C) 2019 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define LOG_TAG "EmulatedLogicalState"
|
|
#define ATRACE_TAG ATRACE_TAG_CAMERA
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include "EmulatedLogicalRequestState.h"
|
|
|
|
#include <log/log.h>
|
|
|
|
#include "vendor_tag_defs.h"
|
|
|
|
namespace android {
|
|
|
|
EmulatedLogicalRequestState::EmulatedLogicalRequestState(uint32_t camera_id)
|
|
: logical_camera_id_(camera_id),
|
|
logical_request_state_(std::make_unique<EmulatedRequestState>(camera_id)) {
|
|
}
|
|
|
|
EmulatedLogicalRequestState::~EmulatedLogicalRequestState() {
|
|
}
|
|
|
|
status_t EmulatedLogicalRequestState::Initialize(
|
|
std::unique_ptr<HalCameraMetadata> static_meta,
|
|
PhysicalDeviceMapPtr physical_devices) {
|
|
if ((physical_devices.get() != nullptr) && (!physical_devices->empty())) {
|
|
zoom_ratio_physical_camera_info_ = GetZoomRatioPhysicalCameraInfo(
|
|
static_meta.get(), physical_devices.get());
|
|
|
|
physical_device_map_ = std::move(physical_devices);
|
|
|
|
static const float ZOOM_RATIO_THRESHOLD = 0.001f;
|
|
for (const auto& one_zoom_range : zoom_ratio_physical_camera_info_) {
|
|
ALOGV("%s: cameraId %d, focalLength %f, zoomRatioRange [%f, %f]",
|
|
__FUNCTION__, one_zoom_range.physical_camera_id,
|
|
one_zoom_range.focal_length, one_zoom_range.min_zoom_ratio,
|
|
one_zoom_range.max_zoom_ratio);
|
|
if (std::abs(one_zoom_range.min_zoom_ratio - 1.0f) < ZOOM_RATIO_THRESHOLD) {
|
|
current_physical_camera_ = one_zoom_range.physical_camera_id;
|
|
}
|
|
}
|
|
|
|
if (zoom_ratio_physical_camera_info_.size() > 1) {
|
|
is_logical_device_ = true;
|
|
for (const auto& it : *physical_device_map_) {
|
|
std::unique_ptr<EmulatedRequestState> physical_request_state =
|
|
std::make_unique<EmulatedRequestState>(it.first);
|
|
auto ret = physical_request_state->Initialize(
|
|
HalCameraMetadata::Clone(it.second.second.get()));
|
|
if (ret != OK) {
|
|
ALOGE("%s: Physical device: %u request state initialization failed!",
|
|
__FUNCTION__, it.first);
|
|
return ret;
|
|
}
|
|
physical_request_states_.emplace(it.first,
|
|
std::move(physical_request_state));
|
|
}
|
|
}
|
|
}
|
|
|
|
return logical_request_state_->Initialize(std::move(static_meta));
|
|
}
|
|
|
|
status_t EmulatedLogicalRequestState::GetDefaultRequest(
|
|
RequestTemplate type,
|
|
std::unique_ptr<HalCameraMetadata>* default_settings /*out*/) {
|
|
return logical_request_state_->GetDefaultRequest(type, default_settings);
|
|
};
|
|
|
|
void EmulatedLogicalRequestState::UpdateActivePhysicalId(
|
|
HalCameraMetadata* result_metadata, uint32_t device_id) {
|
|
if (result_metadata == nullptr) {
|
|
return;
|
|
}
|
|
|
|
auto device_id_str = std::to_string(device_id);
|
|
std::vector<uint8_t> result;
|
|
result.reserve(device_id_str.size() + 1);
|
|
result.insert(result.end(), device_id_str.begin(), device_id_str.end());
|
|
result.push_back('\0');
|
|
|
|
result_metadata->Set(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID,
|
|
result.data(), result.size());
|
|
}
|
|
|
|
std::unique_ptr<HwlPipelineResult>
|
|
EmulatedLogicalRequestState::InitializeLogicalResult(uint32_t pipeline_id,
|
|
uint32_t frame_number) {
|
|
auto ret = logical_request_state_->InitializeResult(pipeline_id, frame_number);
|
|
if (is_logical_device_) {
|
|
if ((physical_camera_output_ids_.get() != nullptr) &&
|
|
(!physical_camera_output_ids_->empty())) {
|
|
ret->physical_camera_results.reserve(physical_camera_output_ids_->size());
|
|
for (const auto& it : *physical_camera_output_ids_) {
|
|
ret->physical_camera_results[it] =
|
|
std::move(physical_request_states_[it]
|
|
->InitializeResult(pipeline_id, frame_number)
|
|
->result_metadata);
|
|
|
|
UpdateActivePhysicalId(ret->physical_camera_results[it].get(), it);
|
|
}
|
|
}
|
|
|
|
UpdateActivePhysicalId(ret->result_metadata.get(), current_physical_camera_);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
status_t EmulatedLogicalRequestState::InitializeLogicalSettings(
|
|
std::unique_ptr<HalCameraMetadata> request_settings,
|
|
std::unique_ptr<std::set<uint32_t>> physical_camera_output_ids,
|
|
EmulatedSensor::LogicalCameraSettings* logical_settings /*out*/) {
|
|
if (logical_settings == nullptr) {
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// All logical and physical devices can potentially receive individual client
|
|
// requests (Currently this is not the case due to HWL API limitations).
|
|
// The emulated sensor can adapt its characteristics and apply most of them
|
|
// independently however the frame duration needs to be the same across all
|
|
// settings.
|
|
// Track the maximum frame duration and override this value at the end for all
|
|
// logical settings.
|
|
nsecs_t max_frame_duration = 0;
|
|
if (is_logical_device_) {
|
|
std::swap(physical_camera_output_ids_, physical_camera_output_ids);
|
|
|
|
for (const auto& physical_request_state : physical_request_states_) {
|
|
// All physical devices will receive requests and will keep
|
|
// updating their respective request state.
|
|
// However only physical devices referenced by client need to propagate
|
|
// and apply their settings.
|
|
EmulatedSensor::SensorSettings physical_sensor_settings;
|
|
auto ret = physical_request_state.second->InitializeSensorSettings(
|
|
HalCameraMetadata::Clone(request_settings.get()),
|
|
&physical_sensor_settings);
|
|
if (ret != OK) {
|
|
ALOGE(
|
|
"%s: Initialization of physical sensor settings for device id: %u "
|
|
"failed!",
|
|
__FUNCTION__, physical_request_state.first);
|
|
return ret;
|
|
}
|
|
|
|
if (physical_camera_output_ids_->find(physical_request_state.first) !=
|
|
physical_camera_output_ids_->end()) {
|
|
logical_settings->emplace(physical_request_state.first,
|
|
physical_sensor_settings);
|
|
if (max_frame_duration < physical_sensor_settings.exposure_time) {
|
|
max_frame_duration = physical_sensor_settings.exposure_time;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
EmulatedSensor::SensorSettings sensor_settings;
|
|
auto ret = logical_request_state_->InitializeSensorSettings(
|
|
std::move(request_settings), &sensor_settings);
|
|
logical_settings->emplace(logical_camera_id_, sensor_settings);
|
|
if (max_frame_duration < sensor_settings.exposure_time) {
|
|
max_frame_duration = sensor_settings.exposure_time;
|
|
}
|
|
|
|
for (auto it : *logical_settings) {
|
|
it.second.frame_duration = max_frame_duration;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::unique_ptr<HalCameraMetadata>
|
|
EmulatedLogicalRequestState::AdaptLogicalCharacteristics(
|
|
std::unique_ptr<HalCameraMetadata> logical_chars,
|
|
PhysicalDeviceMapPtr physical_devices) {
|
|
if ((logical_chars.get() == nullptr) || (physical_devices.get() == nullptr)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// Update 'android.logicalMultiCamera.physicalIds' according to the newly
|
|
// assigned physical ids.
|
|
// Additionally if possible try to emulate a logical camera device backed by
|
|
// physical devices with different focal lengths. Usually real logical
|
|
// cameras like that will have device specific logic to switch between
|
|
// physical sensors. Unfortunately we cannot infer this behavior using only
|
|
// static camera characteristics. Use a simplistic approach of inferring
|
|
// physical camera based on zoom ratio.
|
|
std::vector<ZoomRatioPhysicalCameraInfo> zoom_ratio_physical_camera_info =
|
|
GetZoomRatioPhysicalCameraInfo(logical_chars.get(),
|
|
physical_devices.get());
|
|
|
|
std::vector<uint8_t> physical_ids;
|
|
for (const auto& physical_device : *physical_devices) {
|
|
auto physical_id = std::to_string(physical_device.first);
|
|
physical_ids.insert(physical_ids.end(), physical_id.begin(),
|
|
physical_id.end());
|
|
physical_ids.push_back('\0');
|
|
}
|
|
|
|
if (zoom_ratio_physical_camera_info.size() > 1) {
|
|
float zoom_range[2];
|
|
zoom_range[0] = zoom_ratio_physical_camera_info[0].min_zoom_ratio;
|
|
zoom_range[1] =
|
|
zoom_ratio_physical_camera_info[zoom_ratio_physical_camera_info.size() - 1]
|
|
.max_zoom_ratio;
|
|
logical_chars->Set(ANDROID_CONTROL_ZOOM_RATIO_RANGE, zoom_range, 2);
|
|
|
|
logical_chars->Set(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,
|
|
&zoom_range[1], 1);
|
|
|
|
logical_chars->Set(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
|
|
physical_ids.data(), physical_ids.size());
|
|
|
|
// Possibly needs to be removed at some later point:
|
|
int32_t default_physical_id = physical_devices->begin()->first;
|
|
logical_chars->Set(google_camera_hal::kLogicalCamDefaultPhysicalId,
|
|
&default_physical_id, 1);
|
|
|
|
camera_metadata_ro_entry entry;
|
|
logical_chars->Get(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
|
|
std::set<int32_t> keys(entry.data.i32, entry.data.i32 + entry.count);
|
|
keys.emplace(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID);
|
|
std::vector<int32_t> keys_buffer(keys.begin(), keys.end());
|
|
logical_chars->Set(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,
|
|
keys_buffer.data(), keys_buffer.size());
|
|
|
|
keys.clear();
|
|
keys_buffer.clear();
|
|
logical_chars->Get(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
|
|
keys.insert(entry.data.i32, entry.data.i32 + entry.count);
|
|
// Due to API limitations we currently don't support individual physical requests
|
|
logical_chars->Erase(ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
|
|
keys.erase(ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS);
|
|
keys.emplace(ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
|
|
keys_buffer.insert(keys_buffer.end(), keys.begin(), keys.end());
|
|
logical_chars->Set(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,
|
|
keys_buffer.data(), keys_buffer.size());
|
|
} else {
|
|
ALOGW(
|
|
"%s: The logical camera doesn't support combined zoom ratio ranges. "
|
|
"Emulation "
|
|
"could be"
|
|
" very limited in this case!",
|
|
__FUNCTION__);
|
|
}
|
|
|
|
return logical_chars;
|
|
}
|
|
|
|
status_t EmulatedLogicalRequestState::UpdateRequestForDynamicStreams(
|
|
HwlPipelineRequest* request, const std::vector<EmulatedPipeline>& pipelines,
|
|
const DynamicStreamIdMapType& dynamic_stream_id_map,
|
|
bool use_default_physical_camera) {
|
|
if (request == nullptr) {
|
|
ALOGE("%s: Request must not be null!", __FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
uint32_t pipeline_id = request->pipeline_id;
|
|
if (pipeline_id >= pipelines.size()) {
|
|
ALOGE("%s: Invalid pipeline id %d", __FUNCTION__, pipeline_id);
|
|
return BAD_VALUE;
|
|
}
|
|
|
|
// Only logical camera support dynamic size streams.
|
|
if (!is_logical_device_) return OK;
|
|
|
|
if (request->settings != nullptr) {
|
|
camera_metadata_ro_entry entry;
|
|
auto stat = request->settings->Get(ANDROID_CONTROL_ZOOM_RATIO, &entry);
|
|
if (stat != OK || entry.count != 1) {
|
|
ALOGW("%s: Zoom ratio absent from request, re-using older value!",
|
|
__FUNCTION__);
|
|
return BAD_VALUE;
|
|
}
|
|
if (!use_default_physical_camera) {
|
|
float zoom_ratio = entry.data.f[0];
|
|
for (const auto& one_range : zoom_ratio_physical_camera_info_) {
|
|
if (zoom_ratio >= one_range.min_zoom_ratio &&
|
|
zoom_ratio <= one_range.max_zoom_ratio) {
|
|
current_physical_camera_ = one_range.physical_camera_id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const auto& current_pipeline = pipelines[pipeline_id];
|
|
for (auto& output_buffer : request->output_buffers) {
|
|
auto& current_stream = current_pipeline.streams.at(output_buffer.stream_id);
|
|
if (current_stream.group_id == -1) continue;
|
|
|
|
const auto& stream_ids_for_camera =
|
|
dynamic_stream_id_map.find(current_physical_camera_);
|
|
if (stream_ids_for_camera == dynamic_stream_id_map.end()) {
|
|
ALOGW(
|
|
"%s: Failed to find physical camera id %d in dynamic stream id map!",
|
|
__FUNCTION__, current_physical_camera_);
|
|
continue;
|
|
}
|
|
const auto& stream_id =
|
|
stream_ids_for_camera->second.find(current_stream.group_id);
|
|
if (stream_id == stream_ids_for_camera->second.end()) {
|
|
ALOGW(
|
|
"%s: Failed to find group id %d in dynamic stream id map for camera "
|
|
"%d",
|
|
__FUNCTION__, current_stream.group_id, current_physical_camera_);
|
|
continue;
|
|
}
|
|
|
|
output_buffer.stream_id = stream_id->second;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
std::vector<ZoomRatioPhysicalCameraInfo>
|
|
EmulatedLogicalRequestState::GetZoomRatioPhysicalCameraInfo(
|
|
const HalCameraMetadata* logical_chars,
|
|
const PhysicalDeviceMap* physical_devices) {
|
|
std::vector<ZoomRatioPhysicalCameraInfo> zoom_ratio_physical_camera_info;
|
|
if ((logical_chars == nullptr) || (physical_devices == nullptr)) {
|
|
return zoom_ratio_physical_camera_info;
|
|
}
|
|
|
|
// Get the logical camera's focal length and sensor size
|
|
camera_metadata_ro_entry_t entry;
|
|
auto ret =
|
|
logical_chars->Get(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
|
|
if ((ret != OK) || (entry.count == 0)) {
|
|
return zoom_ratio_physical_camera_info;
|
|
}
|
|
float logical_focal_length = entry.data.f[0];
|
|
ret = logical_chars->Get(ANDROID_SENSOR_INFO_PHYSICAL_SIZE, &entry);
|
|
if ((ret != OK) || (entry.count == 0)) {
|
|
return zoom_ratio_physical_camera_info;
|
|
}
|
|
float logical_sensor_width = entry.data.f[0];
|
|
|
|
// Derive the zoom ratio boundary values for each physical camera id, based on
|
|
// focal lengths and camera sensor physical size.
|
|
for (const auto& physical_device : *physical_devices) {
|
|
ret = physical_device.second.second->Get(
|
|
ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS, &entry);
|
|
if ((ret == OK) && (entry.count > 0)) {
|
|
float focal_length = entry.data.f[0];
|
|
ret = physical_device.second.second->Get(
|
|
ANDROID_SENSOR_INFO_PHYSICAL_SIZE, &entry);
|
|
if ((ret == OK) && (entry.count > 0)) {
|
|
float sensor_width = entry.data.f[0];
|
|
ret = physical_device.second.second->Get(
|
|
ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM, &entry);
|
|
if ((ret == OK) && (entry.count > 0)) {
|
|
float max_digital_zoom = entry.data.f[0];
|
|
// focal length of ultrawide lens
|
|
float min_zoom_ratio = focal_length * logical_sensor_width /
|
|
(logical_focal_length * sensor_width);
|
|
float max_zoom_ratio = max_digital_zoom * min_zoom_ratio;
|
|
zoom_ratio_physical_camera_info.push_back(
|
|
{focal_length, min_zoom_ratio, max_zoom_ratio,
|
|
physical_device.first});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort the mapping by ascending focal length
|
|
std::sort(zoom_ratio_physical_camera_info.begin(),
|
|
zoom_ratio_physical_camera_info.end(),
|
|
[](const ZoomRatioPhysicalCameraInfo& a,
|
|
const ZoomRatioPhysicalCameraInfo& b) {
|
|
return a.focal_length < b.focal_length;
|
|
});
|
|
|
|
// Modify the zoom ratio range for each focal length so that they don't
|
|
// overlap
|
|
for (size_t i = 0; i < zoom_ratio_physical_camera_info.size() - 1; i++) {
|
|
auto& current = zoom_ratio_physical_camera_info[i];
|
|
auto& next = zoom_ratio_physical_camera_info[i + 1];
|
|
if (current.max_zoom_ratio > next.min_zoom_ratio) {
|
|
current.max_zoom_ratio = next.min_zoom_ratio;
|
|
}
|
|
}
|
|
|
|
return zoom_ratio_physical_camera_info;
|
|
}
|
|
|
|
} // namespace android
|