blob: 23d68b7abce5c9b15ae09d15b665cbbc2a401e12 [file] [log] [blame]
/*
* Copyright (C) 2013-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_NDEBUG 0
#define LOG_TAG "EmulatedCameraProviderHwlImpl"
#include <android-base/file.h>
#include <android-base/strings.h>
#include <log/log.h>
#include "camera_common.h"
#include "EmulatedCameraProviderHWLImpl.h"
#include "EmulatedCameraDeviceHWLImpl.h"
#include "EmulatedCameraDeviceSessionHWLImpl.h"
#include "EmulatedSensor.h"
#include "utils/HWLUtils.h"
#include "vendor_tag_defs.h"
namespace android {
// Location of the camera configuration files.
const char* EmulatedCameraProviderHwlImpl::kConfigurationFileLocation =
"/vendor/etc/config/camera.json";
// Array of camera definitions for all cameras available on the device (array).
// Top Level Key.
const char* EmulatedCameraProviderHwlImpl::kCameraDefinitionsKey = "camera_definitions";
std::unique_ptr<EmulatedCameraProviderHwlImpl> EmulatedCameraProviderHwlImpl::Create() {
auto provider =
std::unique_ptr<EmulatedCameraProviderHwlImpl>(new EmulatedCameraProviderHwlImpl());
if (provider == nullptr) {
ALOGE("%s: Creating EmulatedCameraProviderHwlImpl failed.", __FUNCTION__);
return nullptr;
}
status_t res = provider->initialize();
if (res != OK) {
ALOGE("%s: Initializing EmulatedCameraProviderHwlImpl failed: %s (%d).",
__FUNCTION__, strerror(-res), res);
return nullptr;
}
ALOGI("%s: Created EmulatedCameraProviderHwlImpl", __FUNCTION__);
return provider;
}
status_t EmulatedCameraProviderHwlImpl::getTagFromName(const char *name, uint32_t *tag) {
if (name == nullptr || tag == nullptr) {
return BAD_VALUE;
}
size_t nameLength = strlen(name);
// First, find the section by the longest string match
const char *section = NULL;
size_t sectionIndex = 0;
size_t sectionLength = 0;
for (size_t i = 0; i < ANDROID_SECTION_COUNT; ++i) {
const char *str = camera_metadata_section_names[i];
ALOGV("%s: Trying to match against section '%s'", __FUNCTION__, str);
if (strstr(name, str) == name) { // name begins with the section name
size_t strLength = strlen(str);
ALOGV("%s: Name begins with section name", __FUNCTION__);
// section name is the longest we've found so far
if (section == NULL || sectionLength < strLength) {
section = str;
sectionIndex = i;
sectionLength = strLength;
ALOGV("%s: Found new best section (%s)", __FUNCTION__, section);
}
}
}
if (section == NULL) {
return NAME_NOT_FOUND;
} else {
ALOGV("%s: Found matched section '%s' (%zu)",
__FUNCTION__, section, sectionIndex);
}
// Get the tag name component of the name
const char *nameTagName = name + sectionLength + 1; // x.y.z -> z
if (sectionLength + 1 >= nameLength) {
return BAD_VALUE;
}
// Match rest of name against the tag names in that section only
uint32_t candidateTag = 0;
// Match built-in tags (typically android.*)
uint32_t tagBegin, tagEnd; // [tagBegin, tagEnd)
tagBegin = camera_metadata_section_bounds[sectionIndex][0];
tagEnd = camera_metadata_section_bounds[sectionIndex][1];
for (candidateTag = tagBegin; candidateTag < tagEnd; ++candidateTag) {
const char *tagName = get_camera_metadata_tag_name(candidateTag);
if (strcmp(nameTagName, tagName) == 0) {
ALOGV("%s: Found matched tag '%s' (%d)",
__FUNCTION__, tagName, candidateTag);
break;
}
}
if (candidateTag == tagEnd) {
return NAME_NOT_FOUND;
}
*tag = candidateTag;
return OK;
}
status_t getUInt8Value(const Json::Value& value, uint8_t *result/*out*/) {
if (result == nullptr) {
return BAD_VALUE;
}
if (value.isString()) {
errno = 0;
auto intValue = strtol(value.asCString(), nullptr, 10);
if ((intValue >= 0) && (intValue <= UINT8_MAX) && (errno == 0)) {
*result = intValue;
}
} else if (value.isUInt()) {
*result = value.asUInt();
} else {
ALOGE("%s: json type: %d doesn't match with byte tag type",
__FUNCTION__, value.type());
return BAD_VALUE;
}
return OK;
}
status_t getInt32Value(const Json::Value& value, int32_t *result/*out*/) {
if (result == nullptr) {
return BAD_VALUE;
}
if (value.isString()) {
errno = 0;
auto intValue = strtol(value.asCString(), nullptr, 10);
if ((intValue >= INT32_MIN) && (intValue <= INT32_MAX) && (errno == 0)) {
*result = intValue;
}
} else if (value.isInt()) {
*result = value.asInt();
} else {
ALOGE("%s: json type: %d doesn't match with int32 tag type",
__FUNCTION__, value.type());
return BAD_VALUE;
}
return OK;
}
status_t getInt64Value(const Json::Value& value, int64_t *result/*out*/) {
if (result == nullptr) {
return BAD_VALUE;
}
if (value.isString()) {
errno = 0;
auto intValue = strtol(value.asCString(), nullptr, 10);
if ((intValue >= INT64_MIN) && (intValue <= INT64_MAX) && (errno == 0)) {
*result = intValue;
}
} else if (value.isInt64()) {
*result = value.asInt64();
} else {
ALOGE("%s: json type: %d doesn't match with int64 tag type",
__FUNCTION__, value.type());
return BAD_VALUE;
}
return OK;
}
status_t getFloatValue(const Json::Value& value, float *result/*out*/) {
if (result == nullptr) {
return BAD_VALUE;
}
if (value.isString()) {
errno = 0;
auto floatValue = strtof(value.asCString(), nullptr);
if (errno == 0) {
*result = floatValue;
}
} else if (value.isDouble()) { //JsonCPP doesn't seem to support floats.
*result = value.asDouble();
} else {
ALOGE("%s: json type: %d doesn't match with float tag type",
__FUNCTION__, value.type());
return BAD_VALUE;
}
return OK;
}
status_t getDoubleValue(const Json::Value& value, double *result/*out*/) {
if (result == nullptr) {
return BAD_VALUE;
}
if (value.isString()) {
errno = 0;
auto floatValue = strtod(value.asCString(), nullptr);
if (errno == 0) {
*result = floatValue;
}
} else if (value.isDouble()) {
*result = value.asDouble();
} else {
ALOGE("%s: json type: %d doesn't match with double tag type",
__FUNCTION__, value.type());
return BAD_VALUE;
}
return OK;
}
template<typename T, typename funcType>
status_t insertTag(const Json::Value& jsonValue, uint32_t tagId, funcType getValFunc,
HalCameraMetadata *meta/*out*/) {
if (meta == nullptr) {
return BAD_VALUE;
}
std::vector<T> values;
T result;
status_t ret = OK;
if (jsonValue.isArray()) {
values.reserve(jsonValue.size());
for (const auto& val : jsonValue) {
ret = getValFunc(val, &result);
if (ret == OK) {
values.push_back(result);
}
}
} else {
ret = getValFunc(jsonValue, &result);
if (ret == OK) {
values.push_back(result);
}
}
if (ret == OK) {
ret = meta->Set(tagId, values.data(), values.size());
}
return ret;
}
status_t insertRationalTag(const Json::Value& jsonValue, uint32_t tagId,
HalCameraMetadata *meta/*out*/) {
if (meta == nullptr) {
return BAD_VALUE;
}
std::vector<camera_metadata_rational_t> values;
status_t ret = OK;
if (jsonValue.isArray() && ((jsonValue.size() % 2) == 0)) {
values.reserve(jsonValue.size() / 2);
auto it = jsonValue.begin();
while (it != jsonValue.end()) {
camera_metadata_rational_t result;
ret = getInt32Value((*it), &result.numerator); it++;
ret |= getInt32Value((*it), &result.denominator); it++;
if (ret != OK) {
break;
}
values.push_back(result);
}
} else {
ALOGE("%s: json type: %d doesn't match with rational tag type", __FUNCTION__,
jsonValue.type());
return BAD_VALUE;
}
if (ret == OK) {
ret = meta->Set(tagId, values.data(), values.size());
}
return ret;
}
status_t EmulatedCameraProviderHwlImpl::parseCharacteristics(const Json::Value& value) {
if (!value.isObject()) {
ALOGE("%s: Configuration root is not an object", __FUNCTION__);
return false;
}
auto staticMeta = HalCameraMetadata::Create(1, 10);
auto members = value.getMemberNames();
for (const auto& member: members) {
uint32_t tagId;
auto stat = getTagFromName(member.c_str(), &tagId);
if (stat != OK) {
ALOGE("%s: tag %s not supported, skipping!", __func__, member.c_str());
continue;
}
auto tagType = get_camera_metadata_tag_type(tagId);
auto tagValue = value[member.c_str()];
switch (tagType) {
case TYPE_BYTE:
insertTag<uint8_t>(tagValue, tagId, getUInt8Value, staticMeta.get());
break;
case TYPE_INT32:
insertTag<int32_t>(tagValue, tagId, getInt32Value, staticMeta.get());
break;
case TYPE_INT64:
insertTag<int64_t>(tagValue, tagId, getInt64Value, staticMeta.get());
break;
case TYPE_FLOAT:
insertTag<float>(tagValue, tagId, getFloatValue, staticMeta.get());
break;
case TYPE_DOUBLE:
insertTag<double>(tagValue, tagId, getDoubleValue, staticMeta.get());
break;
case TYPE_RATIONAL:
insertRationalTag(tagValue, tagId, staticMeta.get());
break;
default:
ALOGE("%s: Unsupported tag type: %d!", __FUNCTION__, tagType);
}
}
SensorCharacteristics sensorCharacteristics;
auto ret = getSensorCharacteristics(staticMeta.get(), &sensorCharacteristics);
if (ret != OK) {
ALOGE("%s: Unable to extract sensor characteristics!", __FUNCTION__);
return ret;
}
if (!EmulatedSensor::areCharacteristicsSupported(sensorCharacteristics)) {
ALOGE("%s: Sensor characteristics not supported!", __FUNCTION__);
return BAD_VALUE;
}
// TODO: This probably should not be expected by GCH from every HWL impl.
// Adding anyhow to pass CTS
int32_t payloadFrames = 0;
staticMeta->Set(google_camera_hal::kHdrplusPayloadFrames, &payloadFrames, 1);
mStaticMetadata.push_back(std::move(staticMeta));
return OK;
}
status_t EmulatedCameraProviderHwlImpl::initialize() {
std::string config;
if (!android::base::ReadFileToString(kConfigurationFileLocation, &config)) {
ALOGE("%s: Could not open configuration file: %s", __FUNCTION__,
kConfigurationFileLocation);
return false;
}
Json::Reader configReader;
Json::Value root;
if (!configReader.parse(config, root)) {
ALOGE("Could not parse configuration file: %s",
configReader.getFormattedErrorMessages().c_str());
return BAD_VALUE;
}
return parseCharacteristics(root);
}
status_t EmulatedCameraProviderHwlImpl::SetCallback(
const HwlCameraProviderCallback& /*callback*/) {
// TODO: set callbacks
return OK;
}
status_t EmulatedCameraProviderHwlImpl::GetVendorTags(
std::vector<VendorTagSection>* vendor_tag_sections) {
if (vendor_tag_sections == nullptr) {
ALOGE("%s: vendor_tag_sections is nullptr.", __FUNCTION__);
return BAD_VALUE;
}
// No vendor specific tags as of now
return OK;
}
status_t EmulatedCameraProviderHwlImpl::GetVisibleCameraIds(
std::vector<std::uint32_t>* camera_ids) {
if (camera_ids == nullptr) {
ALOGE("%s: camera_ids is nullptr.", __FUNCTION__);
return BAD_VALUE;
}
for (size_t cameraId = 0; cameraId < mStaticMetadata.size(); cameraId++) {
camera_ids->push_back(cameraId);
}
return OK;
}
status_t EmulatedCameraProviderHwlImpl::CreateCameraDeviceHwl(
uint32_t cameraId, std::unique_ptr<CameraDeviceHwl>* camera_device_hwl) {
if (camera_device_hwl == nullptr) {
ALOGE("%s: camera_device_hwl is nullptr.", __FUNCTION__);
return BAD_VALUE;
}
if (cameraId >= mStaticMetadata.size()) {
return BAD_VALUE;
}
std::unique_ptr<HalCameraMetadata> meta = HalCameraMetadata::Clone(
mStaticMetadata[cameraId].get());
*camera_device_hwl = EmulatedCameraDeviceHwlImpl::Create(cameraId, std::move(meta));
if (*camera_device_hwl == nullptr) {
ALOGE("%s: Cannot create EmulatedCameraDeviceHWlImpl.", __FUNCTION__);
return BAD_VALUE;
}
return OK;
}
status_t EmulatedCameraProviderHwlImpl::CreateBufferAllocatorHwl(
std::unique_ptr<CameraBufferAllocatorHwl>* camera_buffer_allocator_hwl) {
if (camera_buffer_allocator_hwl == nullptr) {
ALOGE("%s: camera_buffer_allocator_hwl is nullptr.", __FUNCTION__);
return BAD_VALUE;
}
//TODO: Initialize an emulated buffer allocator
return OK;
}
} // namespace android