blob: af38ff92ff8cda3b7645739dc9ff3c97a8589e1f [file] [log] [blame]
/*
* Copyright (C) 2013-2017 Intel Corporation
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
*
* 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 "Profiles"
#include <expat.h>
#include <limits.h>
#include <system/camera_metadata.h>
#include "LogHelper.h"
#include "CameraProfiles.h"
#include "Metadata.h"
#include "CameraMetadataHelper.h"
#include "IPSLConfParser.h"
#include "Utils.h"
#include "PSLConfParser.h"
/**
* Platform specific implementation
*/
#include "ChromeCameraProfiles.h"
#define STATIC_ENTRY_CAP 256
#define STATIC_DATA_CAP 6688 // TODO: we may need to increase it again if more metadata is added
#define MAX_METADATA_NAME_LENTGTH 128
#define MAX_METADATA_ATTRIBUTE_NAME_LENTGTH 128
#define MAX_METADATA_ATTRIBUTE_VALUE_LENTGTH 6144
NAMESPACE_DECLARATION {
CameraProfiles::CameraProfiles(CameraHWInfo *cameraHWInfo) :
mCurrentDataField(FIELD_INVALID),
mMetadataCache(nullptr),
mSensorIndex(-1),
mXmlSensorIndex(-1),
mItemsCount(-1),
mCameraCommon(cameraHWInfo),
mUseEntry(true)
{
CLEAR(mProfileEnd);
}
status_t CameraProfiles::init()
{
LOG1("@%s", __FUNCTION__);
if (!mCameraCommon) {
LOGE("CameraHWInfo is nullptr");
return BAD_VALUE;
}
mCameraCommon->init(PSLConfParser::getSensorMediaDevicePath());
// Assumption: Driver enumeration order will match the CameraId
// CameraId in camera_profiles.xml. Main camera is always at
// index 0, front camera at index 1.
if (mCameraCommon->mSensorInfo.empty()) {
LOGE("No sensor Info available, exit parsing");
return UNKNOWN_ERROR;
}
mSensorNames = mCameraCommon->mSensorInfo;
mCameraInfoPool.init(MAX_CAMERAS);
for (int i = 0;i < MAX_CAMERAS; i++)
mCharacteristicsKeys[i].clear();
return OK;
}
void CameraProfiles::createConfParser()
{
// Now parse PSL sections for found cameras
for (const auto &cameraIdToCameraInfo : mCameraIdToCameraInfo) {
// get psl parser
CameraInfo *info = cameraIdToCameraInfo.second;
info->parser = PSLConfParser::getInstance(mXmlConfigName, mSensorNames);
}
}
void CameraProfiles::destroyConfParser()
{
PSLConfParser::deleteInstance();
}
int CameraProfiles::getXmlCameraId(int cameraId) const
{
LOG2("@%s", __FUNCTION__);
std::map<int, CameraInfo*>::const_iterator it =
mCameraIdToCameraInfo.find(cameraId);
if (it == mCameraIdToCameraInfo.end()) {
return NAME_NOT_FOUND;
}
return it->second->xmlCameraId;
}
CameraProfiles::~CameraProfiles()
{
LOG2("@%s", __FUNCTION__);
for (unsigned int i = 0; i < mStaticMeta.size(); i++) {
if (mStaticMeta[i])
free_camera_metadata(mStaticMeta[i]);
}
mStaticMeta.clear();
for (const auto &cameraIdToCameraInfo : mCameraIdToCameraInfo) {
CameraInfo *info = cameraIdToCameraInfo.second;
mCameraInfoPool.releaseItem(info);
}
mCameraIdToCameraInfo.clear();
mSensorNames.clear();
}
const CameraCapInfo *CameraProfiles::getCameraCapInfo(int cameraId)
{
// get the psl parser instance for cameraid
IPSLConfParser *parserInstance;
std::map<int, CameraInfo*>::iterator it =
mCameraIdToCameraInfo.find(cameraId);
if (it == mCameraIdToCameraInfo.end()) {
LOGE("Camera id: %d not found. Sensor might not be live", cameraId);
return nullptr;
}
CameraInfo *info = it->second;
parserInstance = info->parser;
if (parserInstance == nullptr) {
LOGE("Failed to get PSL parser instance");
return nullptr;
}
return parserInstance->getCameraCapInfo(cameraId);
}
const CameraCapInfo *CameraProfiles::getCameraCapInfoForXmlCameraId(int xmlCameraId)
{
// get the psl parser instance for cameraid
IPSLConfParser *parserInstance;
int cameraId = -1;
for (const auto &cameraIdToCameraInfo : mCameraIdToCameraInfo) {
if (cameraIdToCameraInfo.second->xmlCameraId == xmlCameraId) {
cameraId = cameraIdToCameraInfo.first;
break;
}
}
if (cameraId == -1)
return nullptr;
CameraInfo *info = mCameraIdToCameraInfo[cameraId];
parserInstance = info->parser;
if (parserInstance == nullptr) {
LOGE("Failed to get PSL parser instance");
return nullptr;
}
return parserInstance->getCameraCapInfo(cameraId);
}
camera_metadata_t *CameraProfiles::constructDefaultMetadata(int cameraId, int requestTemplate)
{
// get the psl parser instance for cameraid
IPSLConfParser *parserInstance;
std::map<int, CameraInfo*>::iterator it =
mCameraIdToCameraInfo.find(cameraId);
if (it == mCameraIdToCameraInfo.end()) {
LOGE("Failed to get camera info for camera:%d", cameraId);
return nullptr;
}
CameraInfo *info = it->second;
parserInstance = info->parser;
if (parserInstance == nullptr) {
LOGE("Failed to get PSL parser instance");
return nullptr;
}
return parserInstance->constructDefaultMetadata(cameraId, requestTemplate);
}
status_t CameraProfiles::addCamera(int cameraId)
{
LOG1("%s: for camera %d", __FUNCTION__, cameraId);
camera_metadata_t * meta = allocate_camera_metadata(STATIC_ENTRY_CAP, STATIC_DATA_CAP);
if (!meta) {
LOGE("No memory for camera metadata!");
return NO_MEMORY;
}
LOG2("Add cameraId: %d to mStaticMeta", cameraId);
mStaticMeta.push_back(meta);
return NO_ERROR;
}
/**
* convertEnum
* Converts from the string provided as src to an enum value.
* It uses a table to convert from the string to an enum value (usually BYTE)
* \param [IN] dest: data buffer where to store the result
* \param [IN] src: pointer to the string to parse
* \param [IN] table: table to convert from string to value
* \param [IN] tableNum: size of the enum table
* \param [IN] type: data type to be parsed (byte, int32, int64 etc..)
* \param [OUT] newDest: pointer to the new write location
*/
int CameraProfiles::convertEnum(void *dest, const char *src, int type,
const metadata_value_t *table, int tableLen,
void **newDest)
{
int ret = 0;
union {
uint8_t * u8;
int32_t * i32;
int64_t * i64;
} data;
*newDest = dest;
data.u8 = (uint8_t *)dest;
/* ignore any spaces in front of the string */
size_t blanks = strspn(src," ");
src = src + blanks;
for (int i = 0; i < tableLen; i++ ) {
if (!strncasecmp(src, table[i].name, STRLEN_S(table[i].name))
&& (STRLEN_S(src) == STRLEN_S(table[i].name))) {
if (type == TYPE_BYTE) {
data.u8[0] = table[i].value;
LOG1("byte - %s: %d -", table[i].name, data.u8[0]);
*newDest = (void*) &data.u8[1];
} else if (type == TYPE_INT32) {
data.i32[0] = table[i].value;
LOG1("int - %s: %d -", table[i].name, data.i32[0]);
*newDest = (void*) &data.i32[1];
} else if (type == TYPE_INT64) {
data.i64[0] = table[i].value;
LOG1("int64 - %s: %" PRId64 " -", table[i].name, data.i64[0]);
*newDest = (void*) &data.i64[1];
}
ret = 1;
break;
}
}
return ret;
}
/**
* parseEnum
* parses an enumeration type or a list of enumeration types it stores the data
* in the member buffer mMetadataCache that is of size mMetadataCacheSize.
*
* \param src: string to be parsed
* \param tagInfo: structure with the description of the static metadata
* \param metadataCacheSize:the upper limited size of the dest buffer
* \param metadataCache: the dest buffer to store the medatada after persed
* \return number of elements parsed
*/
int CameraProfiles::parseEnum(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0;
int maxCount = metadataCacheSize / camera_metadata_type_size[tagInfo->type];
char *endPtr = nullptr;
/**
* pointer to the metadata cache buffer
*/
void *storeBuf = metadataCache;
void *next;
do {
endPtr = (char*) strchr(src, ',');
if (endPtr)
*endPtr = 0;
count += convertEnum(storeBuf, src,tagInfo->type,
tagInfo->enumTable, tagInfo->tableLength, &next);
if (endPtr) {
src = endPtr + 1;
storeBuf = next;
}
} while (count < maxCount && endPtr);
return count;
}
/**
* parseEnumAndNumbers
* parses an enumeration type or a list of enumeration types or tries to convert string to a number
* it stores the data in the member buffer mMetadataCache that is of size mMetadataCacheSize.
*
* \param src: string to be parsed
* \param tagInfo: structure with the description of the static metadata
* \param metadataCacheSize:the upper limited size of the dest buffer
* \param metadataCache: the dest buffer to store the medatada after persed
* \return number of elements parsed
*/
int CameraProfiles::parseEnumAndNumbers(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0;
int maxCount = metadataCacheSize / camera_metadata_type_size[tagInfo->type];
char * endPtr = nullptr;
/**
* pointer to the metadata cache buffer
*/
void *storeBuf = metadataCache;
void *next;
do {
endPtr = (char *) strchr(src, ',');
if (endPtr)
*endPtr = 0;
count += convertEnum(storeBuf, src,tagInfo->type,
tagInfo->enumTable, tagInfo->tableLength, &next);
/* Try to convert value to number */
if (count == 0) {
long int *number = reinterpret_cast<long int*>(storeBuf);
*number = strtol(src, &endPtr, 10);
if (*number == LONG_MAX || *number == LONG_MIN)
LOGW("You might have invalid value in the camera profiles: %s", src);
count++;
}
if (endPtr) {
src = endPtr + 1;
storeBuf = next;
}
} while (count < maxCount && endPtr);
return count;
}
/**
* parseData
* parses a generic array type. It stores the data in the member buffer
* mMetadataCache that is of size mMetadataCacheSize.
*
* \param src: string to be parsed
* \param tagInfo: structure with the description of the static metadata
* \param metadataCacheSize:the upper limited size of the dest buffer
* \param metadataCache: the dest buffer to store the medatada after persed
* \return number of elements parsed
*/
int CameraProfiles::parseData(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int index = 0;
int maxIndex = metadataCacheSize/sizeof(double); // worst case
char * endPtr = nullptr;
union {
uint8_t * u8;
int32_t * i32;
int64_t * i64;
float * f;
double * d;
} data;
data.u8 = (uint8_t *)metadataCache;
do {
switch (tagInfo->type) {
case TYPE_BYTE:
data.u8[index] = (char)strtol(src, &endPtr, 10);
LOG2(" - %d -", data.u8[index]);
break;
case TYPE_INT32:
case TYPE_RATIONAL:
data.i32[index] = strtol(src, &endPtr, 10);
LOG2(" - %d -", data.i32[index]);
break;
case TYPE_INT64:
data.i64[index] = strtol(src, &endPtr, 10);
LOG2(" - %" PRId64 " -", data.i64[index]);
break;
case TYPE_FLOAT:
data.f[index] = strtof(src, &endPtr);
LOG2(" - %8.3f -", data.f[index]);
break;
case TYPE_DOUBLE:
data.d[index] = strtof(src, &endPtr);
LOG2(" - %8.3f -", data.d[index]);
break;
}
index++;
if (endPtr != nullptr) {
if (*endPtr == ',' || *endPtr == 'x')
src = endPtr + 1;
else if (*endPtr == ')')
src = endPtr + 3;
else if (*endPtr == 0)
break;
}
} while (index < maxIndex);
if (tagInfo->type == TYPE_RATIONAL) {
if (index % 2) {
LOGW("Invalid number of entries to define rational (%d) in tag %s."
" It should be even", index, tagInfo->name);
// lets make it even
index -= 1;
}
index = index / 2;
// we divide by 2 because one rational is made of 2 ints
}
return index;
}
const char *CameraProfiles::skipWhiteSpace(const char *src)
{
/* Skip whitespace. (space, tab, newline, vertical tab, feed, carriage return) */
while( *src == '\n' || *src == '\t' || *src == ' ' || *src == '\v' || *src == '\r' || *src == '\f' ) {
src++;
}
return src;
}
/**
* Parses the string with the supported stream configurations
* a stream configuration is made of 3 elements
* - Format
* - Resolution
* - Direction (input or output)
* we parse the string in 3 steps
* example of valid stream configuration is:
* RAW16,4208x3120,INPUT
* \param src: string to be parsed
* \param tagInfo: descriptor of the static metadata. this is the entry from the
* table defined in the autogenerated code
* \param metadataCacheSize:the upper limited size of the dest buffer
* \param metadataCache: the dest buffer to store the medatada after persed
*
* \return number of int32 entries to be stored (i.e. 4 per configuration found)
*/
int CameraProfiles::parseStreamConfig(const char *src,
const metadata_tag_t *tagInfo,
std::vector<MetaValueRefTable> refTables,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0; // entry count
int maxCount = metadataCacheSize/sizeof(int32_t);
int ret;
char * endPtr = nullptr;
int parseStep = 1;
int32_t *i32;
const metadata_value_t * activeTable;
int activeTableLen = 0;
void *storeBuf = metadataCache;
void *next;
if (refTables.size() < 2) {
LOGE("incomplete reference table :%zu", refTables.size());
return count;
}
do {
endPtr = (char *) strchr(src, ',');
if (endPtr)
*endPtr = 0;
if (parseStep == 1) {
activeTable = refTables[0].table;
activeTableLen = refTables[0].tableSize;
} else if (parseStep == 3) {
activeTable = refTables[1].table;
activeTableLen = refTables[1].tableSize;
}
if (parseStep == 1 || parseStep == 3) {
ret = convertEnum(storeBuf, src, tagInfo->type, activeTable,
activeTableLen, &next);
if (ret == 1) {
count++;
storeBuf = next;
} else {
LOGE("Malformed enum in stream configuration %s", src);
goto parseError;
}
} else { // Step 2: Parse the resolution
i32 = reinterpret_cast<int32_t*>(storeBuf);
i32[0] = strtol(src, &endPtr, 10);
if (endPtr == nullptr || *endPtr != 'x') {
LOGE("Malformed resolution in stream configuration");
goto parseError;
}
src = endPtr + 1;
i32[1] = strtol(src, &endPtr, 10);
storeBuf = reinterpret_cast<void*>(&i32[2]);
count += 2;
LOG1(" - %dx%d -", i32[0], i32[1]);
}
if (endPtr) {
src = endPtr + 1;
src = skipWhiteSpace(src);
parseStep++;
/* parsing steps go from 1 to 3 */
if (parseStep == 4) {
parseStep = 1;
LOG1("Stream Configuration found");
}
} else {
break;
}
} while (count < maxCount);
if (endPtr != nullptr) {
LOGW("Stream configuration stream too long for parser");
}
/**
* Total number of entries per stream configuration is 4
* - one for the format
* - two for the resolution
* - one for the direction
* The total entry count should be multiple of 4
*/
if (count % 4) {
LOGE("Malformed string for stream configuration."
" ignoring last %d entries", count % 4);
count -= count % 4;
}
return count;
parseError:
LOGE("Error parsing stream configuration ");
return 0;
}
/**
* parseAvailableKeys
* This method is used to parse the following two static metadata tags:
* android.request.availableRequestKeys
* android.request.availableResultKeys
*
* It uses the auto-generated table metadataNames to look for all the non
* static tags.
*/
int CameraProfiles::parseAvailableKeys(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0; // entry count
int maxCount = metadataCacheSize/camera_metadata_type_size[tagInfo->type];
size_t tableSize = ELEMENT(metadataNames);
size_t blanks, tokenSize;
const char *token;
const char *cleanToken;
const char delim = ',';
int32_t* storeBuf = (int32_t*)metadataCache;
std::vector<std::string> tokens;
getTokens(src, delim, tokens);
for (size_t i = 0; i < tokens.size(); i++) {
token = tokens.at(i).c_str();
/* ignore any spaces in front of the string */
blanks = strspn(token," ");
cleanToken = token + blanks;
/**
* Parse the token without blanks.
* TODO: Add support for simple wildcard to allow things like
* android.request.*
*/
tokenSize = STRLEN_S(cleanToken);
for (unsigned int i = 0; i< tableSize; i++) {
if (strncmp(cleanToken, metadataNames[i].name, tokenSize) == 0) {
storeBuf[count] = metadataNames[i].value;
count++;
}
}
if (count >= maxCount) {
LOGW("Too many keys found (%d)- ignoring the rest", count);
/* if this happens then we should increase the size of the
* mMetadataCache
*/
break;
}
}
return count;
}
/**
* Parses the string with the avaialble input-output formats map
* a format map is made of 3 elements
* - Input Format
* - Number output formats it can be converted in to
* - List of the output formats.
* we parse the string in 3 steps
* example of valid input-output formats map is:
* RAW_OPAQUE,3,BLOB,IMPLEMENTATION_DEFINED,YCbCr_420_888
*
* \param src: string to be parsed
* \param tagInfo: descriptor of the static metadata. this is the entry from the
* table defined in the autogenerated code
* \param metadataCacheSize:the upper limit size of the dest buffer
* \param metadataCache: the dest buffer to store the medatada after persed
*
* \return number of int32 entries to be stored
*/
int CameraProfiles::parseAvailableInputOutputFormatsMap(const char *src,
const metadata_tag_t *tagInfo,
std::vector<MetaValueRefTable> refTables,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0; // entry count
int maxCount = metadataCacheSize/camera_metadata_type_size[tagInfo->type];
int ret;
char * endPtr = nullptr;
int parseStep = 1;
int32_t *i32;
int numOutputFormats = 0;
const metadata_value_t * activeTable;
int activeTableLen = 0;
void *storeBuf = metadataCache;
void *next;
if (refTables.size() < 1) {
LOGE("incomplete reference table :%zu", refTables.size());
return count;
}
do {
endPtr = (char *) strchr(src, ',');
if (endPtr)
*endPtr = 0;
if (parseStep == 1) { // Step 1 parse the input format
if (STRLEN_S(src) == 0) break;
// detect empty string. It means we are done, so get out of the loop
activeTable = refTables[0].table;
activeTableLen = refTables[0].tableSize;
ret = convertEnum(storeBuf, src, tagInfo->type, activeTable,
activeTableLen, &next);
if (ret == 1) {
count++;
storeBuf = next;
} else {
LOGE("Malformed enum in format map %s", src);
break;
}
} else if (parseStep == 2) { // Step 2: Parse the num of output formats
i32 = reinterpret_cast<int32_t*>(storeBuf);
i32[0] = strtol(src, &endPtr, 10);
numOutputFormats = i32[0];
count += 1;
storeBuf = reinterpret_cast<void*>(&i32[1]);
LOGD("Num of output formats = %d", i32[0]);
} else { // Step3 parse the output formats
activeTable = refTables[0].table;
activeTableLen = refTables[0].tableSize;
for (int i = 0; i < numOutputFormats; i++) {
ret = convertEnum(storeBuf, src, tagInfo->type, activeTable,
activeTableLen, &next);
if (ret == 1) {
count += 1;
if (endPtr == nullptr) return count;
src = endPtr + 1;
storeBuf = next;
} else {
LOGE("Malformed enum in format map %s", src);
break;
}
if (i < numOutputFormats - 1) {
endPtr = (char *) strchr(src, ',');
if (endPtr)
*endPtr = 0;
}
}
}
if (endPtr) {
src = endPtr + 1;
src = skipWhiteSpace(src);
parseStep++;
/* parsing steps go from 1 to 3 */
if (parseStep == 4) {
parseStep = 1;
}
}
} while (count < maxCount && endPtr);
if (endPtr != nullptr) {
LOGW("Formats Map string too long for parser");
}
return count;
}
int CameraProfiles::parseSizes(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t* metadataCache)
{
HAL_TRACE_CALL(1);
int entriesFound = 0;
entriesFound = parseData(src, tagInfo, metadataCacheSize, metadataCache);
if (entriesFound % 2) {
LOGE("Odd number of entries (%d), resolutions should have an even "
"number of entries", entriesFound);
entriesFound -= 1; //make it even Ignore the last one
}
return entriesFound;
}
int CameraProfiles::parseImageFormats(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t *metadataCache)
{
/**
* DEPRECATED in V 3.2: TODO: add warning and extra checks
*/
HAL_TRACE_CALL(1);
int entriesFound = 0;
entriesFound = parseEnum(src, tagInfo, metadataCacheSize, metadataCache);
return entriesFound;
}
int CameraProfiles::parseRectangle(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t *metadataCache)
{
HAL_TRACE_CALL(1);
int entriesFound = 0;
entriesFound = parseData(src, tagInfo, metadataCacheSize, metadataCache);
if (entriesFound % 4) {
LOGE("incorrect number of entries (%d), rectangles have 4 values",
entriesFound);
entriesFound -= entriesFound % 4; //round to multiple of 4
}
return entriesFound;
}
int CameraProfiles::parseBlackLevelPattern(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t *metadataCache)
{
HAL_TRACE_CALL(1);
int entriesFound = 0;
entriesFound = parseData(src, tagInfo, metadataCacheSize, metadataCache);
if (entriesFound % 4) {
LOGE("incorrect number of entries (%d), black level pattern have 4 values",
entriesFound);
entriesFound -= entriesFound % 4; //round to multiple of 4
}
return entriesFound;
}
int CameraProfiles::parseStreamConfigDuration(const char *src,
const metadata_tag_t *tagInfo,
std::vector<MetaValueRefTable> refTables,
int metadataCacheSize,
int64_t *metadataCache)
{
HAL_TRACE_CALL(1);
int count = 0; // entry count
int maxCount = metadataCacheSize/camera_metadata_type_size[tagInfo->type];
int ret;
char * endPtr = nullptr;
int parseStep = 1;
int64_t *i64;
const metadata_value_t * activeTable;
int activeTableLen = 0;
void *storeBuf = metadataCache;
void *next;
if (refTables.size() < 1) {
LOGE("incomplete reference table :%zu", refTables.size());
return count;
}
do {
endPtr = (char *) strchr(src, ',');
if (endPtr)
*endPtr = 0;
if (parseStep == 1) { // Step 1 parse the format
if (STRLEN_S(src) == 0) break;
// detect empty string. It means we are done, so get out of the loop
activeTable = refTables[0].table;
activeTableLen = refTables[0].tableSize;
ret = convertEnum(storeBuf, src, tagInfo->type, activeTable,
activeTableLen, &next);
if (ret == 1) {
count++;
storeBuf = next;
} else {
LOGE("Malformed enum in stream configuration duration %s", src);
break;
}
} else if (parseStep == 2) { // Step 2: Parse the resolution
i64 = reinterpret_cast<int64_t*>(storeBuf);
i64[0] = strtol(src, &endPtr, 10);
if (endPtr == nullptr || *endPtr != 'x') {
LOGE("Malformed resolution in stream duration configuration");
break;
}
src = endPtr + 1;
i64[1] = strtol(src, &endPtr, 10);
storeBuf = reinterpret_cast<void*>(&i64[2]);
count += 2;
LOG1(" - %" PRId64 "x%" PRId64 " -", i64[0], i64[1]);
} else { // Step3 parse the duration
i64 = reinterpret_cast<int64_t*>(storeBuf);
if (endPtr)
i64[0] = strtol(src, &endPtr, 10);
else
i64[0] = strtol(src, nullptr, 10); // Do not update endPtr
storeBuf = reinterpret_cast<void*>(&i64[1]);
count += 1;
LOG1(" - %" PRId64 " ns -", i64[0]);
}
if (endPtr) {
src = endPtr + 1;
src = skipWhiteSpace(src);
parseStep++;
/* parsing steps go from 1 to 3 */
if (parseStep == 4) {
parseStep = 1;
LOG1("Stream Configuration Duration found");
}
}
} while (count < maxCount && endPtr);
if (endPtr != nullptr) {
LOGW("Stream configuration duration string too long for parser");
}
/**
* Total number of entries per stream configuration is 4
* - one for the format
* - two for the resolution
* - one for the duration
* The total entry count should be multiple of 4
*/
if (count % 4) {
LOGE("Malformed string for stream config duration."
" ignoring last %d entries", count % 4);
count -= count % 4;
}
return count;
}
/**
*
* Checks whether the sensor named in a profile is present in the list of
* runtime detected sensors.
* The result of this method helps to decide whether to use a particular profile
* from the XML file.
*
* \param[in] detectedSensors vector with the description of the runtime
* detected sensors.
* \param[in] profileName name of the sensor present in the XML config file.
* \param[in] cameraId camera Id for the sensor name in the XML.
*
* \return true if the sensor named in the profile is available in HW.
*/
bool CameraProfiles::isSensorPresent(std::vector<SensorDriverDescriptor> &detectedSensors,
const char *profileName, int cameraId) const
{
for (unsigned int i = 0; i < detectedSensors.size(); i++) {
/*
* Logic for legacy platforms with only 1-2 sensors.
*/
if ((detectedSensors[i].mIspPort == PRIMARY && cameraId == 0) ||
(detectedSensors[i].mIspPort == SECONDARY && cameraId == 1) ||
(detectedSensors[i].mIspPort == UNKNOWN_PORT)) {
if (detectedSensors[i].mSensorName == profileName) {
LOG1("@%s: mUseEntry is true, mSensorIndex = %d, name = %s",
__FUNCTION__, cameraId, profileName);
return true;
}
}
/*
* Logic for new platforms that support more than 2 sensors.
* To uniquely match an XML profile to a sensor present in HW we will
* use 2 pieces of information:
* - sensor name
* - CSI port
* Current implementation only uses sensor name. CSI port is needed in
* cases where we have same sensor name in different ports.
* TODO add this to XML part
*/
if (detectedSensors[i].mSensorDevType == SENSOR_DEVICE_MC) {
if (detectedSensors[i].mSensorName == profileName) {
LOG1("@%s: mUseEntry is true, mSensorIndex = %d, name = %s",
__FUNCTION__, cameraId, profileName);
return true;
}
}
}
return false;
}
/**
* This function will check which field that the parser parses to.
*
* The field is set to 5 types.
* FIELD_INVALID FIELD_SENSOR_COMMON FIELD_SENSOR_ANDROID_METADATA FIELD_SENSOR_VENDOR_METADATA and FIELD_COMMON
*
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraProfiles::checkField(CameraProfiles *profiles,
const char *name,
const char **atts)
{
if (!strcmp(name, "Profiles")) {
mXmlSensorIndex = atoi(atts[1]);
if (mXmlSensorIndex > MAX_CAMERAS) {
LOGE("ERROR: bad camera id %d!", mSensorIndex);
return;
}
profiles->mUseEntry = false;
int attIndex = 2;
if (atts[attIndex]) {
if (strcmp(atts[attIndex], "name") == 0) {
mSensorIndex++;
LOG1("@%s: mSensorIndex = %d, name = %s, mSensorNames.size():%zu",
__FUNCTION__, mSensorIndex,
atts[attIndex + 1], profiles->mSensorNames.size());
profiles->mUseEntry = isSensorPresent(profiles->mSensorNames,
atts[attIndex + 1],
mSensorIndex);
if (profiles->mUseEntry) {
mCameraIdToSensorName.insert(make_pair(mSensorIndex, std::string(atts[attIndex + 1])));
}
} else {
LOGE("unknown attribute atts[%d] = %s", attIndex, atts[attIndex]);
}
} else {
// for platforms that don't have the name field in the camera profiles.
profiles->mUseEntry = true;
mSensorIndex++;
}
if (profiles->mUseEntry
&& mSensorIndex >= mStaticMeta.size()
&& mStaticMeta.size() < profiles->mSensorNames.size())
addCamera(mSensorIndex);
} else if (strcmp(name, "Supported_hardware") == 0) {
mCurrentDataField = FIELD_SUPPORTED_HARDWARE;
mItemsCount = -1;
} else if (strcmp(name, "Android_metadata") == 0) {
mCurrentDataField = FIELD_ANDROID_STATIC_METADATA;
mItemsCount = -1;
} else if (strcmp(name, "Common") == 0) {
mCurrentDataField = FIELD_COMMON;
mItemsCount = -1;
}
LOG1("@%s: name:%s, field %d", __FUNCTION__, name, mCurrentDataField);
return;
}
void CameraProfiles::handleSupportedHardware(const char *name, const char **atts)
{
LOG1("@%s, type:%s", __FUNCTION__, name);
if (strcmp(atts[0], "value") != 0) {
LOGE("name:%s, atts[0]:%s, xml format wrong", name, atts[0]);
return;
}
if (strcmp(name, "hwType") == 0) {
CameraInfo *info = nullptr;
mCameraInfoPool.acquireItem(&info);
if (info != nullptr) {
info->parser = nullptr;
info->hwType = atts[1];
info->xmlCameraId = mXmlSensorIndex;
mCameraIdToCameraInfo.insert(std::make_pair(mSensorIndex, info));
LOG2("Add sensor: %s to mCameraIdToCameraInfo with key: %d", name, mSensorIndex);
} else {
LOGE("Failed to get camera info for sensor index %d", mSensorIndex);
}
} else {
LOGE("Unhandled xml attribute in Supported_hardware");
}
}
/**
* This function will handle all the common related elements.
*
* It will be called in the function startElement
*
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraProfiles::handleCommon(const char *name, const char **atts)
{
LOG1("@%s, name:%s, atts[0]:%s", __FUNCTION__, name, atts[0]);
if (strcmp(atts[0], "value") != 0) {
LOGE("name:%s, atts[0]:%s, xml format wrong", name, atts[0]);
return;
}
}
bool CameraProfiles::validateStaticMetadata(const char *name, const char **atts)
{
/**
* string validation
*/
size_t nameSize = strnlen(name, MAX_METADATA_NAME_LENTGTH);
size_t attrNameSize = strnlen(atts[0], MAX_METADATA_ATTRIBUTE_NAME_LENTGTH);
size_t attrValueSize = strnlen(atts[1], MAX_METADATA_ATTRIBUTE_VALUE_LENTGTH);
if ((attrValueSize == MAX_METADATA_ATTRIBUTE_VALUE_LENTGTH) ||
(attrNameSize == MAX_METADATA_ATTRIBUTE_NAME_LENTGTH) ||
(nameSize == MAX_METADATA_NAME_LENTGTH)) {
LOGW("Warning XML strings too long ignoring this tag %s", name);
return false;
}
if ((strncmp(atts[0], "value", attrNameSize) != 0) ||
(attrValueSize == 0)) {
LOGE("Check atts failed! name: %s, atts[0]: \"%s\", atts[1]: \"%s\", the format of xml is wrong!", name, atts[0], atts[1]);
return false;
}
return true;
}
const metadata_tag_t *CameraProfiles::findTagInfo(const char *name,
const metadata_tag_t *tagsTable,
unsigned int size)
{
size_t nameSize = strnlen(name, MAX_METADATA_NAME_LENTGTH);
unsigned int index = 0;
const metadata_tag_t *tagInfo = nullptr;
for (index = 0; index < size; index++) {
if (!strncmp(name, tagsTable[index].name, nameSize)) {
tagInfo = &tagsTable[index];
break;
}
}
if (index >= size) {
LOGW("Parser does not support tag %s! - ignoring", name);
}
return tagInfo;
}
int CameraProfiles::parseGenericTypes(const char *src,
const metadata_tag_t *tagInfo,
int metadataCacheSize,
int64_t *metadataCache)
{
int count = 0;
switch (tagInfo->arrayTypedef) {
case BOOLEAN:
case ENUM_LIST:
count = parseEnum(src, tagInfo, metadataCacheSize, metadataCache);
break;
case RANGE_INT:
case RANGE_LONG:
count = parseData(src, tagInfo, metadataCacheSize, metadataCache);
break;
case SIZE_F:
case SIZE:
count = parseSizes(src, tagInfo, metadataCacheSize, metadataCache);
break;
case RECTANGLE:
count = parseRectangle(src, tagInfo, metadataCacheSize, metadataCache);
break;
case IMAGE_FORMAT:
count = parseImageFormats(src, tagInfo, metadataCacheSize, metadataCache);
break;
case BLACK_LEVEL_PATTERN:
count = parseBlackLevelPattern(src, tagInfo, metadataCacheSize, metadataCache);
break;
case TYPEDEF_NONE: /* Single values*/
if (tagInfo->enumTable) {
count = parseEnum(src, tagInfo, metadataCacheSize, metadataCache);
} else {
count = parseData(src, tagInfo, metadataCacheSize, metadataCache);
}
break;
default:
LOGW("Unsupported typedef %s", tagInfo->name);
break;
}
return count;
}
/**
* the callback function of the libexpat for handling of one element start
*
* When it comes to the start of one element. This function will be called.
*
* \param userData: the pointer we set by the function XML_SetUserData.
* \param name: the element's name.
*/
void CameraProfiles::startElement(void *userData, const char *name, const char **atts)
{
CameraProfiles *profiles = (CameraProfiles *)userData;
if (profiles->mCurrentDataField == FIELD_INVALID) {
profiles->checkField(profiles, name, atts);
return;
}
LOG2("@%s: name:%s, for sensor %d", __FUNCTION__, name, profiles->mSensorIndex);
profiles->mItemsCount++;
switch (profiles->mCurrentDataField) {
case FIELD_SUPPORTED_HARDWARE:
if (profiles->mUseEntry)
profiles->handleSupportedHardware(name, atts);
break;
case FIELD_ANDROID_STATIC_METADATA:
if (profiles->mUseEntry)
profiles->handleAndroidStaticMetadata(name, atts);
break;
case FIELD_COMMON:
if (profiles->mStaticMeta.size() > 0)
profiles->handleCommon(name, atts);
break;
default:
LOGE("line:%d, go to default handling", __LINE__);
break;
}
}
/**
* the callback function of the libexpat for handling of one element end
*
* When it comes to the end of one element. This function will be called.
*
* \param userData: the pointer we set by the function XML_SetUserData.
* \param name: the element's name.
*/
void CameraProfiles::endElement(void *userData, const char *name)
{
CameraProfiles *profiles = (CameraProfiles *)userData;
if (!strcmp(name, "Profiles")) {
profiles->mCurrentDataField = FIELD_INVALID;
if (profiles->mUseEntry)
profiles->mProfileEnd[profiles->mSensorIndex] = true;
} else if (!strcmp(name, "Supported_hardware")
|| !strcmp(name, "Android_metadata")
|| !strcmp(name, "Common")) {
profiles->mCurrentDataField = FIELD_INVALID;
profiles->mItemsCount = -1;
}
return;
}
/**
* Get camera configuration from xml file
*
* The function will read the xml configuration file firstly.
* Then it will parse out the camera settings.
* The camera setting is stored inside this CameraProfiles class.
*
*/
void CameraProfiles::getDataFromXmlFile(void)
{
int done;
void *pBuf = nullptr;
FILE *fp = nullptr;
LOG1("@%s", __FUNCTION__);
camera_metadata_t *currentMeta = nullptr;
status_t res;
int tag = ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS;
fp = ::fopen(mXmlConfigName.c_str(), "r");
if (nullptr == fp) {
LOGE("line:%d, fp is nullptr", __LINE__);
return;
}
XML_Parser parser = ::XML_ParserCreate(nullptr);
if (nullptr == parser) {
LOGE("line:%d, parser is nullptr", __LINE__);
goto exit;
}
::XML_SetUserData(parser, this);
::XML_SetElementHandler(parser, startElement, endElement);
pBuf = ::operator new(BUFFERSIZE);
mMetadataCache = new int64_t[METADATASIZE];
do {
int len = (int)::fread(pBuf, 1, BUFFERSIZE, fp);
if (!len) {
if (ferror(fp)) {
clearerr(fp);
goto exit;
}
}
done = len < BUFFERSIZE;
if (XML_Parse(parser, (const char *)pBuf, len, done) == XML_STATUS_ERROR) {
LOGE("line:%d, XML_Parse error", __LINE__);
goto exit;
}
} while (!done);
if (mStaticMeta.size() > 0) {
for (unsigned int i = 0; i < mStaticMeta.size(); i++) {
currentMeta = mStaticMeta.at(i);
if (currentMeta == nullptr) {
LOGE("can't get the static metadata");
goto exit;
}
// update REQUEST_AVAILABLE_CHARACTERISTICS_KEYS
int *keys = mCharacteristicsKeys[i].data();
res = MetadataHelper::updateMetadata(currentMeta, tag, keys, mCharacteristicsKeys[i].size());
if (res != OK)
LOGE("call add/update_camera_metadata_entry fail for request.availableCharacteristicsKeys");
}
}
exit:
if (parser)
::XML_ParserFree(parser);
::operator delete(pBuf);
if (mMetadataCache) {
delete [] mMetadataCache;
mMetadataCache = nullptr;
}
if (fp)
::fclose(fp);
}
CameraHwType CameraProfiles::getCameraHwforId(int cameraId)
{
LOG2("@%s cameraId: %d", __FUNCTION__, cameraId);
std::map<int, CameraInfo*>::iterator it =
mCameraIdToCameraInfo.find(cameraId);
if (it == mCameraIdToCameraInfo.end()) {
LOGE("Camera id not found, BUG, this should not happen!!mSensorIndex = %d", cameraId);
return SUPPORTED_HW_UNKNOWN;
}
CameraInfo *info = it->second;
std::string hwType = info->hwType;
if (hwType == "SUPPORTED_HW_RKISP1") {
return SUPPORTED_HW_RKISP1;
} else
LOGE("ERROR: Camera HW type wrong in xml");
return SUPPORTED_HW_UNKNOWN;
}
void CameraProfiles::dumpSupportedHWSection(int cameraId) {
LOGD("@%s", __FUNCTION__);
std::map<int, CameraInfo*>::iterator it =
mCameraIdToCameraInfo.find(cameraId);
if (it == mCameraIdToCameraInfo.end()) {
LOGE("Camera id not found, BUG, this should not happen!!mSensorIndex = %d", cameraId);
return;
}
CameraInfo *info = it->second;
LOGD("element name hwType element value = %s", info->hwType.c_str());
}
void CameraProfiles::dumpStaticMetadataSection(int cameraId)
{
LOGD("@%s", __FUNCTION__);
if (mStaticMeta.size() > 0)
MetadataHelper::dumpMetadata(mStaticMeta[cameraId]);
else {
LOGE("Camera isn't added, unable to get the static metadata");
}
}
void CameraProfiles::dumpCommonSection()
{
LOGD("@%s", __FUNCTION__);
LOGD("element name: boardName, element value = %s", mCameraCommon->mBoardName.c_str());
LOGD("element name: productName, element value = %s", mCameraCommon->productName());
LOGD("element name: manufacturerName, element value = %s", mCameraCommon->manufacturerName());
LOGD("element name: mSupportDualVideo, element value = %d", mCameraCommon-> mSupportDualVideo);
LOGD("element name: supportExtendedMakernote, element value = %d", mCameraCommon->mSupportExtendedMakernote);
}
// To be modified when new elements or sections are added
// Use LOGD for traces to be visible
void CameraProfiles::dump()
{
LOGD("===========================@%s======================", __FUNCTION__);
for (unsigned int i = 0; i <= mSensorIndex; i++) {
dumpSupportedHWSection(i);
dumpStaticMetadataSection(i);
}
dumpCommonSection();
LOGD("===========================end======================");
}
} NAMESPACE_DECLARATION_END