| /* |
| * 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 |