blob: 6ad921d4487b18ee7f2bd86ff4e9632d2e2d4e24 [file] [log] [blame]
/*
* 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 "EmulatedCameraDevSession"
#define ATRACE_TAG ATRACE_TAG_CAMERA
#include "EmulatedCameraDeviceSessionHWLImpl.h"
#include <android/hardware/graphics/common/1.2/types.h>
#include <hardware/gralloc.h>
#include <inttypes.h>
#include <log/log.h>
#include <utils/Trace.h>
#include <memory>
#include "EmulatedSensor.h"
#include "utils.h"
#include "utils/HWLUtils.h"
namespace android {
using google_camera_hal::utils::GetSensorActiveArraySize;
using google_camera_hal::utils::HasCapability;
using android::hardware::graphics::common::V1_2::Dataspace;
std::unique_ptr<EmulatedCameraZoomRatioMapperHwlImpl>
EmulatedCameraZoomRatioMapperHwlImpl::Create(
const std::unordered_map<uint32_t, std::pair<Dimension, Dimension>>& dims) {
auto zoom_ratio_mapper_hwl_impl =
std::make_unique<EmulatedCameraZoomRatioMapperHwlImpl>(dims);
return zoom_ratio_mapper_hwl_impl;
}
EmulatedCameraZoomRatioMapperHwlImpl::EmulatedCameraZoomRatioMapperHwlImpl(
const std::unordered_map<uint32_t, std::pair<Dimension, Dimension>>& dims)
: camera_ids_to_dimensions_(dims) {
}
bool EmulatedCameraZoomRatioMapperHwlImpl::GetActiveArrayDimensionToBeUsed(
uint32_t camera_id, const HalCameraMetadata* settings,
Dimension* active_array_dimension) const {
auto dim_it = camera_ids_to_dimensions_.find(camera_id);
if (settings == nullptr || active_array_dimension == nullptr ||
dim_it == camera_ids_to_dimensions_.end()) {
// default request / camera id not found
return false;
}
camera_metadata_ro_entry entry = {};
status_t res = settings->Get(ANDROID_SENSOR_PIXEL_MODE, &entry);
if (res != OK) {
// return default res dimension
*active_array_dimension = dim_it->second.second;
return true;
}
if (entry.data.u8[0] == ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) {
// return max res mode dimension
*active_array_dimension = dim_it->second.first;
} else {
*active_array_dimension = dim_it->second.second;
}
return true;
}
std::unique_ptr<EmulatedCameraDeviceSessionHwlImpl>
EmulatedCameraDeviceSessionHwlImpl::Create(
uint32_t camera_id, std::unique_ptr<HalCameraMetadata> static_meta,
PhysicalDeviceMapPtr physical_devices,
std::shared_ptr<EmulatedTorchState> torch_state) {
ATRACE_CALL();
if (static_meta.get() == nullptr) {
return nullptr;
}
auto session = std::unique_ptr<EmulatedCameraDeviceSessionHwlImpl>(
new EmulatedCameraDeviceSessionHwlImpl(std::move(physical_devices),
torch_state));
if (session == nullptr) {
ALOGE("%s: Creating EmulatedCameraDeviceSessionHwlImpl failed",
__FUNCTION__);
return nullptr;
}
status_t res = session->Initialize(camera_id, std::move(static_meta));
if (res != OK) {
ALOGE("%s: Initializing EmulatedCameraDeviceSessionHwlImpl failed: %s(%d)",
__FUNCTION__, strerror(-res), res);
return nullptr;
}
return session;
}
static std::pair<Dimension, Dimension> GetArrayDimensions(
uint32_t camera_id, const HalCameraMetadata* metadata) {
google_camera_hal::Rect active_array_size;
Dimension active_array_size_dimension;
Dimension active_array_size_dimension_maximum_resolution;
status_t ret = GetSensorActiveArraySize(metadata, &active_array_size);
if (ret != OK) {
ALOGE("%s: Failed to get sensor active array size for camera id %d",
__FUNCTION__, (int)camera_id);
return std::pair<Dimension, Dimension>();
}
active_array_size_dimension = {
active_array_size.right - active_array_size.left + 1,
active_array_size.bottom - active_array_size.top + 1};
active_array_size_dimension_maximum_resolution = active_array_size_dimension;
if (HasCapability(
metadata,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_ULTRA_HIGH_RESOLUTION_SENSOR)) {
status_t ret = GetSensorActiveArraySize(metadata, &active_array_size,
/*maximum_resolution=*/true);
if (ret != OK) {
ALOGE(
"%s: Failed to get max resolution sensor active array size for "
"camera id %d",
__FUNCTION__, (int)camera_id);
return std::pair<Dimension, Dimension>();
}
active_array_size_dimension_maximum_resolution = {
active_array_size.right - active_array_size.left + 1,
active_array_size.bottom - active_array_size.top + 1};
}
return std::make_pair(active_array_size_dimension_maximum_resolution,
active_array_size_dimension);
}
status_t EmulatedCameraDeviceSessionHwlImpl::Initialize(
uint32_t camera_id, std::unique_ptr<HalCameraMetadata> static_meta) {
camera_id_ = camera_id;
static_metadata_ = std::move(static_meta);
stream_configuration_map_ =
std::make_unique<StreamConfigurationMap>(*static_metadata_);
stream_configuration_map_max_resolution_ =
std::make_unique<StreamConfigurationMap>(*static_metadata_, true);
camera_metadata_ro_entry_t entry;
auto ret = static_metadata_->Get(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &entry);
if (ret != OK) {
ALOGE("%s: Unable to extract ANDROID_REQUEST_PIPELINE_MAX_DEPTH, %s (%d)",
__FUNCTION__, strerror(-ret), ret);
return ret;
}
max_pipeline_depth_ = entry.data.u8[0];
std::unordered_map<uint32_t, std::pair<Dimension, Dimension>>
camera_ids_to_dimensions;
camera_ids_to_dimensions[camera_id] =
GetArrayDimensions(camera_id, static_metadata_.get());
ret = GetSensorCharacteristics(static_metadata_.get(), &sensor_chars_);
if (ret != OK) {
ALOGE("%s: Unable to extract sensor characteristics %s (%d)", __FUNCTION__,
strerror(-ret), ret);
return ret;
}
ret = SupportsSessionHalBufManager(static_metadata_.get(),
&supports_session_hal_buf_manager_);
if (ret != OK) {
ALOGE("%s: Unable to get sensor hal buffer manager support %s (%d)",
__FUNCTION__, strerror(-ret), ret);
return ret;
}
logical_chars_.emplace(camera_id_, sensor_chars_);
for (const auto& it : *physical_device_map_) {
SensorCharacteristics physical_chars;
auto stat = GetSensorCharacteristics(it.second.second.get(), &physical_chars);
if (stat == OK) {
logical_chars_.emplace(it.first, physical_chars);
} else {
ALOGE("%s: Unable to extract physical device: %u characteristics %s (%d)",
__FUNCTION__, it.first, strerror(-ret), ret);
return ret;
}
camera_ids_to_dimensions[it.first] =
GetArrayDimensions(it.first, it.second.second.get());
physical_stream_configuration_map_.emplace(
it.first,
std::make_unique<StreamConfigurationMap>(*it.second.second.get()));
physical_stream_configuration_map_max_resolution_.emplace(
it.first, std::make_unique<StreamConfigurationMap>(
*it.second.second.get(), true));
}
zoom_ratio_mapper_hwl_impl_ = std::move(
EmulatedCameraZoomRatioMapperHwlImpl::Create(camera_ids_to_dimensions));
return InitializeRequestProcessor();
}
status_t EmulatedCameraDeviceSessionHwlImpl::InitializeRequestProcessor() {
sp<EmulatedSensor> emulated_sensor = new EmulatedSensor();
auto logical_chars = std::make_unique<LogicalCharacteristics>(logical_chars_);
auto ret = emulated_sensor->StartUp(camera_id_, std::move(logical_chars));
if (ret != OK) {
ALOGE("%s: Failed on sensor start up %s (%d)", __FUNCTION__, strerror(-ret),
ret);
return ret;
}
request_processor_ = std::make_shared<EmulatedRequestProcessor>(
camera_id_, emulated_sensor, session_callback_);
request_processor_->InitializeSensorQueue(request_processor_);
return request_processor_->Initialize(
HalCameraMetadata::Clone(static_metadata_.get()),
ClonePhysicalDeviceMap(physical_device_map_));
}
EmulatedCameraDeviceSessionHwlImpl::~EmulatedCameraDeviceSessionHwlImpl() {
if (torch_state_.get() != nullptr) {
torch_state_->ReleaseFlashHw();
}
}
status_t EmulatedCameraDeviceSessionHwlImpl::ConstructDefaultRequestSettings(
RequestTemplate type, std::unique_ptr<HalCameraMetadata>* default_settings) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
return request_processor_->GetDefaultRequest(type, default_settings);
}
status_t EmulatedCameraDeviceSessionHwlImpl::ConfigurePipeline(
uint32_t physical_camera_id, HwlPipelineCallback hwl_pipeline_callback,
const StreamConfiguration& request_config,
const StreamConfiguration& /*overall_config*/, uint32_t* pipeline_id) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
if (pipeline_id == nullptr) {
ALOGE("%s pipeline_id is nullptr", __FUNCTION__);
return BAD_VALUE;
}
if (pipelines_built_) {
ALOGE("%s Cannot configure pipelines after calling BuildPipelines()",
__FUNCTION__);
return ALREADY_EXISTS;
}
if (!EmulatedSensor::IsStreamCombinationSupported(
physical_camera_id, request_config, *stream_configuration_map_,
*stream_configuration_map_max_resolution_,
physical_stream_configuration_map_,
physical_stream_configuration_map_max_resolution_, logical_chars_)) {
ALOGE("%s: Stream combination not supported!", __FUNCTION__);
return BAD_VALUE;
}
if ((physical_camera_id != camera_id_) &&
(physical_device_map_.get() != nullptr)) {
if (physical_device_map_->find(physical_camera_id) ==
physical_device_map_->end()) {
ALOGE("%s: Camera: %d doesn't include physical device with id: %u",
__FUNCTION__, camera_id_, physical_camera_id);
return BAD_VALUE;
}
}
*pipeline_id = pipelines_.size();
EmulatedPipeline emulated_pipeline{.cb = hwl_pipeline_callback,
.physical_camera_id = physical_camera_id,
.pipeline_id = *pipeline_id,};
emulated_pipeline.streams.reserve(request_config.streams.size());
for (const auto& stream : request_config.streams) {
bool is_input = stream.stream_type == google_camera_hal::StreamType::kInput;
emulated_pipeline.streams.emplace(
stream.id,
EmulatedStream(
{{.id = stream.id,
.override_format =
is_input ? stream.format
: EmulatedSensor::OverrideFormat(
stream.format, stream.dynamic_profile),
.producer_usage = is_input ? 0
: GRALLOC_USAGE_SW_WRITE_OFTEN |
GRALLOC_USAGE_HW_CAMERA_WRITE |
GRALLOC_USAGE_HW_CAMERA_READ,
.consumer_usage = 0,
.max_buffers = max_pipeline_depth_,
.override_data_space =
(stream.dynamic_profile ==
ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10) &&
(stream.format ==
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)
? static_cast<android_dataspace_t>(
Dataspace::BT2020_ITU_HLG)
: stream.data_space,
.is_physical_camera_stream = stream.is_physical_camera_stream,
.physical_camera_id = stream.physical_camera_id},
.width = stream.width,
.height = stream.height,
.buffer_size = stream.buffer_size,
.is_input = is_input,
.group_id = stream.group_id,
.use_case = stream.use_case,
.color_space = stream.color_space}));
if (stream.group_id != -1 && stream.is_physical_camera_stream) {
// TODO: For quad bayer camera, the logical camera id should be used if
// this is not a physical camera.
dynamic_stream_id_map_[stream.physical_camera_id][stream.group_id] =
stream.id;
}
if (!stream.is_physical_camera_stream &&
(stream.format == HAL_PIXEL_FORMAT_RAW16)) {
has_raw_stream_ = true;
}
}
pipelines_.push_back(emulated_pipeline);
return OK;
}
status_t EmulatedCameraDeviceSessionHwlImpl::GetConfiguredHalStream(
uint32_t pipeline_id, std::vector<HalStream>* hal_streams) const {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
if (hal_streams == nullptr) {
ALOGE("%s hal_streams is nullptr", __FUNCTION__);
return BAD_VALUE;
}
if (!pipelines_built_) {
ALOGE("%s No pipeline was built.", __FUNCTION__);
return NO_INIT;
}
if (pipeline_id >= pipelines_.size()) {
ALOGE("%s: Unknown pipeline ID: %u", __FUNCTION__, pipeline_id);
return NAME_NOT_FOUND;
}
const auto& streams = pipelines_[pipeline_id].streams;
hal_streams->reserve(streams.size());
for (const auto& it : streams) {
hal_streams->push_back(it.second);
}
return OK;
}
status_t EmulatedCameraDeviceSessionHwlImpl::BuildPipelines() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
if (pipelines_built_) {
ALOGE("%s Pipelines have already been built!", __FUNCTION__);
return ALREADY_EXISTS;
} else if (pipelines_.size() == 0) {
ALOGE("%s No pipelines have been configured yet!", __FUNCTION__);
return NO_INIT;
}
status_t ret = OK;
if (request_processor_ == nullptr) {
ret = InitializeRequestProcessor();
}
if (ret == OK) {
pipelines_built_ = true;
}
return OK;
}
status_t EmulatedCameraDeviceSessionHwlImpl::ShouldUseHalBufferManager(
bool* result) {
if (result == nullptr) {
ALOGE("%s result is nullptr", __FUNCTION__);
return BAD_VALUE;
}
*result = false;
if (!pipelines_built_) {
ALOGE("%s: Pipelines haven't been built yet", __FUNCTION__);
return INVALID_OPERATION;
}
if (!supports_session_hal_buf_manager_) {
return OK;
}
// Heuristic which doesn't necessarily correspond to real scenarios
if (pipelines_.size() >= 1 && pipelines_[0].streams.size() >= 2) {
*result = true;
}
return OK;
}
void EmulatedCameraDeviceSessionHwlImpl::DestroyPipelines() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
if (!pipelines_built_) {
// Not an error - nothing to destroy
ALOGV("%s nothing to destroy", __FUNCTION__);
return;
}
pipelines_built_ = false;
has_raw_stream_ = false;
pipelines_.clear();
request_processor_ = nullptr;
}
status_t EmulatedCameraDeviceSessionHwlImpl::CheckOutputFormatsForInput(
const HwlPipelineRequest& request,
const std::unordered_map<uint32_t, EmulatedStream>& streams,
const std::unique_ptr<StreamConfigurationMap>& stream_configuration_map,
android_pixel_format_t input_format) {
auto output_formats =
stream_configuration_map->GetValidOutputFormatsForInput(input_format);
for (const auto& output_buffer : request.output_buffers) {
auto output_stream = streams.at(output_buffer.stream_id);
if (output_formats.find(output_stream.override_format) ==
output_formats.end()) {
ALOGE(
"%s: Reprocess request with input format: 0x%x to output "
"format: 0x%x"
" not supported!",
__FUNCTION__, input_format, output_stream.override_format);
return BAD_VALUE;
}
}
return OK;
}
status_t EmulatedCameraDeviceSessionHwlImpl::SubmitRequests(
uint32_t frame_number, std::vector<HwlPipelineRequest>& requests) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
// Check whether reprocess request has valid/supported outputs.
for (const auto& request : requests) {
if (!request.input_buffers.empty()) {
for (const auto& input_buffer : request.input_buffers) {
const auto& streams = pipelines_[request.pipeline_id].streams;
auto input_stream = streams.at(input_buffer.stream_id);
if ((CheckOutputFormatsForInput(request, streams,
stream_configuration_map_,
input_stream.override_format) != OK) &&
(CheckOutputFormatsForInput(
request, streams, stream_configuration_map_max_resolution_,
input_stream.override_format) != OK)) {
return BAD_VALUE;
}
}
}
}
if (error_state_) {
ALOGE("%s session is in error state and cannot process further requests",
__FUNCTION__);
return INVALID_OPERATION;
}
return request_processor_->ProcessPipelineRequests(
frame_number, requests, pipelines_, dynamic_stream_id_map_,
has_raw_stream_);
}
status_t EmulatedCameraDeviceSessionHwlImpl::Flush() {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
return request_processor_->Flush();
}
uint32_t EmulatedCameraDeviceSessionHwlImpl::GetCameraId() const {
return camera_id_;
}
std::vector<uint32_t> EmulatedCameraDeviceSessionHwlImpl::GetPhysicalCameraIds()
const {
if ((physical_device_map_.get() == nullptr) ||
(physical_device_map_->empty())) {
return std::vector<uint32_t>{};
}
std::vector<uint32_t> ret;
ret.reserve(physical_device_map_->size());
for (const auto& it : *physical_device_map_) {
ret.push_back(it.first);
}
return ret;
}
status_t EmulatedCameraDeviceSessionHwlImpl::GetCameraCharacteristics(
std::unique_ptr<HalCameraMetadata>* characteristics) const {
ATRACE_CALL();
if (characteristics == nullptr) {
return BAD_VALUE;
}
(*characteristics) = HalCameraMetadata::Clone(static_metadata_.get());
if (*characteristics == nullptr) {
ALOGE("%s metadata clone failed", __FUNCTION__);
return NO_MEMORY;
}
return OK;
}
status_t EmulatedCameraDeviceSessionHwlImpl::GetPhysicalCameraCharacteristics(
uint32_t physical_camera_id,
std::unique_ptr<HalCameraMetadata>* characteristics) const {
ATRACE_CALL();
if (characteristics == nullptr) {
return BAD_VALUE;
}
if (physical_device_map_.get() == nullptr) {
ALOGE("%s: Camera: %d doesn't have physical device support!", __FUNCTION__,
camera_id_);
return BAD_VALUE;
}
if (physical_device_map_->find(physical_camera_id) ==
physical_device_map_->end()) {
ALOGE("%s: Camera: %d doesn't include physical device with id: %u",
__FUNCTION__, camera_id_, physical_camera_id);
return BAD_VALUE;
}
(*characteristics) = HalCameraMetadata::Clone(
physical_device_map_->at(physical_camera_id).second.get());
return OK;
}
void EmulatedCameraDeviceSessionHwlImpl::SetSessionCallback(
const HwlSessionCallback& hwl_session_callback) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(api_mutex_);
session_callback_ = hwl_session_callback;
if (request_processor_ != nullptr) {
request_processor_->SetSessionCallback(hwl_session_callback);
}
}
} // namespace android