blob: 444555c9ef625a2ece5cf5b0dc8c347c1deebc02 [file] [log] [blame]
/*
* Copyright (C) 2015-2020 Intel Corporation
* Copyright 2008-2017, 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 "CameraParser"
#include <string.h>
#include <expat.h>
#include <memory>
#include "iutils/CameraLog.h"
#include "iutils/Utils.h"
#include "metadata/ParameterHelper.h"
#include "PlatformData.h"
#include "CameraParser.h"
using std::string;
using std::vector;
#include "v4l2/NodeInfo.h"
namespace icamera {
#define LIBCAMHAL_PROFILE_NAME "libcamhal_profile.xml"
CameraParser::CameraParser(MediaControl *mc, PlatformData::StaticCfg *cfg) :
mStaticCfg(cfg),
mCurrentDataField(FIELD_INVALID),
mSensorNum(0),
mCurrentSensor(0),
pCurrentCam(nullptr),
mInMediaCtlCfg(false),
mInStaticMetadata(false),
mMC(mc),
mMetadataCache(nullptr) {
LOGXML("@%s", __func__);
CheckError(mc == nullptr || cfg == nullptr, VOID_VALUE,
"@%s, passed parameters are wrong, mc:%p, data:%p", __func__, mc, cfg);
mGenericStaticMetadataToTag = {
{"ae.lockAvailable", CAMERA_AE_LOCK_AVAILABLE},
{"awb.lockAvailable", CAMERA_AWB_LOCK_AVAILABLE},
{"control.availableModes", CAMERA_CONTROL_AVAILABLE_MODES},
{"control.availableSceneModes", CAMERA_CONTROL_AVAILABLE_SCENE_MODES},
{"control.maxRegions", CAMERA_CONTROL_MAX_REGIONS},
{"statistics.info.availableFaceDetectModes", CAMERA_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES},
{"statistics.info.maxFaceCount", CAMERA_STATISTICS_INFO_MAX_FACE_COUNT},
{"sensor.info.activeArraySize", CAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE},
{"sensor.info.pixelArraySize", CAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE},
{"sensor.info.physicalSize", CAMERA_SENSOR_INFO_PHYSICAL_SIZE},
{"sensor.info.sensitivityRange", CAMERA_SENSOR_INFO_SENSITIVITY_RANGE},
{"sensor.info.exposureTimeRange", CAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE},
{"sensor.info.colorFilterArrangement", CAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT},
{"sensor.availableTestPatternModes", CAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES},
{"sensor.orientation", CAMERA_SENSOR_ORIENTATION},
{"sensor.opaqueRawSize", CAMERA_SENSOR_OPAQUE_RAW_SIZE},
{"shading.availableModes", CAMERA_SHADING_AVAILABLE_MODES},
{"lens.facing", CAMERA_LENS_FACING},
{"lens.info.availableApertures", CAMERA_LENS_INFO_AVAILABLE_APERTURES},
{"lens.info.availableFilterDensities", CAMERA_LENS_INFO_AVAILABLE_FILTER_DENSITIES},
{"lens.info.availableFocalLengths", CAMERA_LENS_INFO_AVAILABLE_FOCAL_LENGTHS},
{"lens.info.availableOpticalStabilization", CAMERA_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION},
{"lens.info.hyperfocalDistance", CAMERA_LENS_INFO_HYPERFOCAL_DISTANCE},
{"lens.info.minimumFocusDistance", CAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE},
{"lens.info.shadingMapSize", CAMERA_LENS_INFO_SHADING_MAP_SIZE},
{"lens.info.focusDistanceCalibration", CAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION},
{"request.maxNumOutputStreams", CAMERA_REQUEST_MAX_NUM_OUTPUT_STREAMS},
{"request.maxNumInputStreams", CAMERA_REQUEST_MAX_NUM_INPUT_STREAMS},
{"request.pipelineMaxDepth", CAMERA_REQUEST_PIPELINE_MAX_DEPTH},
{"request.availableCapabilities", CAMERA_REQUEST_AVAILABLE_CAPABILITIES},
{"scaler.availableInputOutputFormatsMap", CAMERA_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP},
{"scaler.availableStreamConfigurations", CAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS},
{"scaler.availableMinFrameDurations", CAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS},
{"scaler.availableStallDurations", CAMERA_SCALER_AVAILABLE_STALL_DURATIONS},
{"reprocess.maxCaptureStall", CAMERA_REPROCESS_MAX_CAPTURE_STALL},
{"jpeg.maxSize", CAMERA_JPEG_MAX_SIZE},
{"jpeg.availableThumbnailSizes", CAMERA_JPEG_AVAILABLE_THUMBNAIL_SIZES},
{"edge.availableEdgeModes", CAMERA_EDGE_AVAILABLE_EDGE_MODES},
{"hotPixel.availableHotPixelModes", CAMERA_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES},
{"noiseReduction.availableNoiseReductionModes", CAMERA_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES},
{"tonemap.maxCurvePoints", CAMERA_TONEMAP_MAX_CURVE_POINTS},
{"tonemap.availableToneMapModes", CAMERA_TONEMAP_AVAILABLE_TONE_MAP_MODES},
{"info.supportedHardwareLevel", CAMERA_INFO_SUPPORTED_HARDWARE_LEVEL},
{"sync.maxLatency", CAMERA_SYNC_MAX_LATENCY},
};
mMetadataCache = new long[mMetadataCacheSize];
// Get common data from libcamhal_profile.xml
int ret = getDataFromXmlFile(LIBCAMHAL_PROFILE_NAME);
CheckError(ret != OK, VOID_VALUE, "Failed to get libcamhal profile data frome %s",
LIBCAMHAL_PROFILE_NAME);
getSensorDataFromXmlFile();
if(gLogLevel & CAMERA_DEBUG_LOG_LEVEL2) {
dumpSensorInfo();
}
}
CameraParser::~CameraParser()
{
delete []mMetadataCache;
}
/**
* Replacing $I2CBUS with the real mI2CBus if the value contains the string "$I2CBUS"
* one example: "imx319 $I2CBUS"
* Replacing $CSI_PORT with the real mCsiPort if the value contains the string "$CSI_PORT"
* one example: "Intel IPU6 CSI-2 $CSI_PORT"
*
* \param profiles: the pointer of the CameraParser.
* \param value: camera information.
* \return: if the value contains the string, it will be replaced.
*/
string CameraParser::replaceStringInXml(CameraParser *profiles, const char *value)
{
string valueTmp;
CheckError(value == nullptr, valueTmp, "value is nullptr");
valueTmp = value;
string::size_type found = string::npos;
if ((found = valueTmp.find("$I2CBUS")) != string::npos) {
valueTmp.replace(found, sizeof("$I2CBUS"), profiles->mI2CBus);
LOGXML("@%s, sensor full name is %s", __func__, valueTmp.c_str());
} else if ((found = valueTmp.find("$CSI_PORT")) != string::npos) {
valueTmp.replace(found, sizeof("$CSI_PORT"), profiles->mCsiPort);
LOGXML("@%s, csi entity full name is %s", __func__, valueTmp.c_str());
}
return valueTmp;
}
/**
* This function will check which field that the parser parses to.
*
* The field is set to 3 types.
* FIELD_INVALID FIELD_SENSOR and FIELD_COMMON
*
* \param profiles: the pointer of the CameraParser.
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraParser::checkField(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s", __func__, name);
if (strcmp(name, "CameraSettings") == 0) {
profiles->mCurrentDataField = FIELD_INVALID;
return;
} else if (strcmp(name, "Sensor") == 0) {
profiles->mSensorNum++;
profiles->mCurrentSensor = profiles->mSensorNum - 1;
if (profiles->mCurrentSensor >= 0 && profiles->mCurrentSensor < MAX_CAMERA_NUMBER) {
profiles->pCurrentCam = new PlatformData::StaticCfg::CameraInfo;
int idx = 0;
string sensorEntityName;
string sinkEntityName;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "name") == 0) {
profiles->pCurrentCam->sensorName = val;
} else if (strcmp(key, "description") == 0) {
profiles->pCurrentCam->sensorDescription = val;
}
idx += 2;
}
if (!profiles->pCurrentCam->sensorName.empty() &&
(profiles->mAvailableSensor.find(profiles->pCurrentCam->sensorName) !=
profiles->mAvailableSensor.end())) {
/* parameters information format example:
sinkEntityName is "Intel IPU6 CSI-2 1"
profiles->pCurrentCam->sensorName is "ov8856-wf"
sensorName is "ov8856"
*/
string sinkEntityName = profiles->mAvailableSensor[profiles->pCurrentCam->sensorName];
profiles->mCsiPort = sinkEntityName.substr(sinkEntityName.find_last_of(' ') + 1);
string sensorName = profiles->pCurrentCam->sensorName;
sensorName = sensorName.substr(0, (sensorName.find_last_of('-')));
profiles->mMC->getI2CBusAddress(sensorName, sinkEntityName, &profiles->mI2CBus);
LOGXML("@%s, mI2CBus:%s, cisPort:%s", __func__,
profiles->mI2CBus.c_str(), profiles->mCsiPort.c_str());
}
profiles->mMetadata.clear();
profiles->mCurrentDataField = FIELD_SENSOR;
return;
}
} else if (strcmp(name, "Common") == 0) {
profiles->mCurrentDataField = FIELD_COMMON;
return;
}
LOGE("@%s, name:%s, atts[0]:%s, xml format wrong", __func__, name, atts[0]);
return;
}
/**
* This function will handle all the common related elements.
*
* It will be called in the function startElement
*
* \param profiles: the pointer of the CameraParser.
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraParser::handleCommon(CameraParser *profiles, const char *name, const char **atts)
{
CheckError(strcmp(atts[0], "value") != 0 || (atts[1] == nullptr), VOID_VALUE
,"@%s, name:%s, atts[0]:%s or atts[1] is nullptr, xml format wrong", __func__, name, atts[0]);
LOGXML("@%s, name:%s, atts[0]:%s, atts[1]: %s", __func__, name, atts[0], atts[1]);
CommonConfig *cfg = &profiles->mStaticCfg->mCommonConfig;
if (strcmp(name, "version") == 0) {
cfg->xmlVersion = atof(atts[1]);
} else if (strcmp(name, "platform") == 0) {
cfg->ipuName = atts[1];
} else if (strcmp(name, "availableSensors") == 0) {
parseXmlConvertStrings(atts[1], cfg->availableSensors, convertCharToString);
} else if (strcmp(name, "useGpuTnr") == 0) {
cfg->isGpuTnrEnabled = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "cameraNumber") == 0) {
cfg->cameraNumber = atoi(atts[1]);
} else if (strcmp(name, "stillTnrPrior") == 0) {
cfg->isStillTnrPrior = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "tnrParamForceUpdate") == 0) {
cfg->isTnrParamForceUpdate = strcmp(atts[1], "true") == 0;
}
}
/**
* This function will handle all the sensor related elements.
*
* It will be called in the function startElement
*
* \param profiles: the pointer of the CameraParser.
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraParser::handleSensor(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s, profiles->mCurrentSensor:%d", __func__, name, profiles->mCurrentSensor);
CheckError(strcmp(atts[0], "value") != 0 || (atts[1] == nullptr), VOID_VALUE
,"@%s, name:%s, atts[0]:%s or atts[1] is nullptr, xml format wrong", __func__, name, atts[0]);
LOGXML("@%s, name:%s, atts[0]:%s, atts[1]:%s", __func__, name, atts[0], atts[1]);
if (strcmp(name, "supportedISysSizes") == 0) {
parseSizesList(atts[1], pCurrentCam->mSupportedISysSizes);
for (const auto &s : pCurrentCam->mSupportedISysSizes)
LOGXML("@%s, mSupportedISysSizes: width:%d, height:%d", __func__,
s.width, s.height);
} else if (strcmp(name, "supportedISysFormat") == 0) {
getSupportedFormat(atts[1], pCurrentCam->mSupportedISysFormat);
} else if (strcmp(name, "iSysRawFormat") == 0) {
pCurrentCam->mISysRawFormat = CameraUtils::string2PixelCode(atts[1]);
} else if (strcmp(name, "configModeToStreamId") == 0) {
char* srcDup = strdup(atts[1]);
CheckError(!srcDup, VOID_VALUE, "Create a copy of source string failed.");
char* endPtr = (char*)strchr(srcDup, ',');
if (endPtr) {
*endPtr = 0;
ConfigMode configMode = CameraUtils::getConfigModeByName(srcDup);
int streamId = atoi(endPtr + 1);
pCurrentCam->mConfigModeToStreamId[configMode] = streamId;
}
free(srcDup);
} else if (strcmp(name, "pSysFormat") == 0) {
getSupportedFormat(atts[1], pCurrentCam->mPSysFormat);
} else if (strcmp(name, "enableAIQ") == 0) {
pCurrentCam->mEnableAIQ = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "useCrlModule") == 0) {
pCurrentCam->mUseCrlModule = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "skipFrameV4L2Error") == 0) {
pCurrentCam->mSkipFrameV4L2Error = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "useSensorDigitalGain") == 0) {
pCurrentCam->mUseSensorDigitalGain = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "useIspDigitalGain") == 0) {
pCurrentCam->mUseIspDigitalGain = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "preRegisterBuffer") == 0) {
pCurrentCam->mNeedPreRegisterBuffers = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "enableFrameSyncCheck") == 0) {
pCurrentCam->mFrameSyncCheckEnabled = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "lensName") == 0) {
profiles->mMC->getVCMI2CAddr(atts[1], &pCurrentCam->mLensName);
} else if (strcmp(name, "lensHwType") == 0) {
if (strcmp(atts[1], "LENS_VCM_HW") == 0) {
pCurrentCam->mLensHwType = LENS_VCM_HW;
} else {
LOGE("unknown Lens HW type %s, set to LENS_NONE_HW", atts[1]);
pCurrentCam->mLensHwType = LENS_NONE_HW;
}
} else if (strcmp(name, "autoSwitchType") == 0) {
if (strcmp(atts[1], "full") == 0) {
pCurrentCam->mAutoSwitchType = AUTO_SWITCH_FULL;
} else {
pCurrentCam->mAutoSwitchType = AUTO_SWITCH_PSYS;
}
} else if (strcmp(name, "lensCloseCode") == 0) {
pCurrentCam->mLensCloseCode = atoi(atts[1]);
} else if (strcmp(name, "cITMaxMargin") == 0) {
pCurrentCam->mCITMaxMargin = atoi(atts[1]);
} else if (strcmp(name, "ltmGainLag") == 0) {
pCurrentCam->mLtmGainLag = atoi(atts[1]);
} else if (strcmp(name, "enableLtmThread") == 0) {
pCurrentCam->mEnableLtmThread = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "enableLtmDefog") == 0) {
pCurrentCam->mEnableLtmDefog = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "enableLtm") == 0) {
pCurrentCam->mLtmEnabled = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "maxSensorDg") == 0) {
pCurrentCam->mMaxSensorDigitalGain = atoi(atts[1]);
} else if (strcmp(name, "sensorDgType") == 0) {
if (strcmp(atts[1], "type_2_x") == 0) {
pCurrentCam->mSensorDgType = SENSOR_DG_TYPE_2_X;
} else if (strcmp(atts[1], "type_x") == 0) {
pCurrentCam->mSensorDgType = SENSOR_DG_TYPE_X;
} else {
LOGE("unknown sensor digital gain type:%s, set to SENSOR_DG_TYPE_NONE", atts[1]);
pCurrentCam->mSensorDgType = SENSOR_DG_TYPE_NONE;
}
} else if (strcmp(name, "digitalGainLag") == 0) {
pCurrentCam->mDigitalGainLag = atoi(atts[1]);
} else if (strcmp(name, "exposureLag") == 0) {
pCurrentCam->mExposureLag = atoi(atts[1]);
} else if (strcmp(name, "graphSettingsFile") == 0) {
pCurrentCam->mGraphSettingsFile = atts[1];
} else if (strcmp(name, "graphSettingsType") == 0) {
if (strcmp(atts[1], "coupled") == 0) {
pCurrentCam->mGraphSettingsType = COUPLED;
} else if (strcmp(atts[1], "dispersed") == 0) {
pCurrentCam->mGraphSettingsType = DISPERSED;
} else {
LOGW("unknown graph settings type %s, set to COUPLED", atts[1]);
pCurrentCam->mGraphSettingsType = COUPLED;
}
} else if (strcmp(name, "gainLag") == 0) {
pCurrentCam->mAnalogGainLag = atoi(atts[1]);
} else if (strcmp(name, "customAicLibraryName") == 0) {
pCurrentCam->mCustomAicLibraryName = atts[1];
} else if (strcmp(name, "custom3ALibraryName") == 0){
pCurrentCam->mCustom3ALibraryName = atts[1];
} else if (strcmp(name, "yuvColorRangeMode") == 0) {
if (strcmp(atts[1],"full") == 0) {
pCurrentCam->mYuvColorRangeMode = CAMERA_FULL_MODE_YUV_COLOR_RANGE;
} else if (strcmp(atts[1],"reduced") == 0) {
pCurrentCam->mYuvColorRangeMode = CAMERA_REDUCED_MODE_YUV_COLOR_RANGE;
}
} else if (strcmp(name, "initialSkipFrame") == 0) {
pCurrentCam->mInitialSkipFrame = atoi(atts[1]);
} else if (strcmp(name, "maxRawDataNum") == 0) {
pCurrentCam->mMaxRawDataNum = atoi(atts[1]);
} else if (strcmp(name, "topBottomReverse") == 0) {
pCurrentCam->mTopBottomReverse = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "maxRequestsInflight") == 0) {
pCurrentCam->mMaxRequestsInflight = atoi(atts[1]);
} else if (strcmp(name, "psysContinueStats") == 0) {
pCurrentCam->mPsysContinueStats = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "preferredBufQSize") == 0) {
pCurrentCam->mPreferredBufQSize = atoi(atts[1]);
} else if (strcmp(name, "pipeSwitchDelayFrame") == 0) {
pCurrentCam->mPipeSwitchDelayFrame = atoi(atts[1]);
} else if (strcmp(name, "supportedTuningConfig") == 0) {
parseSupportedTuningConfig(atts[1], pCurrentCam->mSupportedTuningConfig);
} else if (strcmp(name, "enableAiqd") == 0) {
pCurrentCam->mEnableAiqd = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "testPatternMap") == 0) {
int size = strlen(atts[1]);
char src[size + 1];
MEMCPY_S(src, size, atts[1], size);
src[size] = '\0';
int32_t mode = TEST_PATTERN_OFF;
char* savePtr = nullptr;
char* tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
if (strcmp(tablePtr, "Off") == 0) {
mode = TEST_PATTERN_OFF;
} else if (strcmp(tablePtr, "ColorBars") == 0) {
mode = COLOR_BARS;
} else if (strcmp(tablePtr, "SolidColor") == 0) {
mode = SOLID_COLOR;
} else if (strcmp(tablePtr, "ColorBarsFadeToGray") == 0) {
mode = COLOR_BARS_FADE_TO_GRAY;
} else if (strcmp(tablePtr, "PN9") == 0) {
mode = PN9;
} else if (strcmp(tablePtr, "CUSTOM1") == 0) {
mode = TEST_PATTERN_CUSTOM1;
} else {
LOGE("Test pattern string %s is unknown, please check", tablePtr);
return;
}
tablePtr = strtok_r(nullptr, ",", &savePtr);
CheckError(tablePtr == nullptr, VOID_VALUE, "Driver test pattern is nullptr");
pCurrentCam->mTestPatternMap[mode] = atoi(tablePtr);
tablePtr = strtok_r(nullptr, ",", &savePtr);
}
} else if (strcmp(name, "lardTags") == 0) {
parseLardTags(atts[1], pCurrentCam->mLardTagsConfig);
} else if (strcmp(name, "availableConfigModeForAuto") == 0) {
parseXmlConvertStrings(atts[1], pCurrentCam->mConfigModesForAuto, CameraUtils::getConfigModeByName);
} else if (strcmp(name, "supportedAeMultiExpRange") == 0) {
parseMultiExpRange(atts[1]);
} else if (strcmp(name, "dvsType") == 0) {
if (strcmp(atts[1], "MORPH_TABLE") == 0) {
pCurrentCam->mDVSType = MORPH_TABLE;
} else if (strcmp(atts[1], "IMG_TRANS") == 0) {
pCurrentCam->mDVSType = IMG_TRANS;
}
} else if (strcmp(name, "pslOutputMapForRotation") == 0) {
parseOutputMap(atts[1], pCurrentCam->mOutputMap);
} else if (strcmp(name, "maxNvmDataSize") == 0) {
pCurrentCam->mMaxNvmDataSize = atoi(atts[1]);
} else if (strcmp(name, "nvmDirectory") == 0) {
pCurrentCam->mNvmDirectory = atts[1];
} else if (strcmp(name, "cameraModuleToAiqbMap") == 0) {
int size = strlen(atts[1]);
char src[size + 1];
MEMCPY_S(src, size, atts[1], size);
src[size] = '\0';
char* savePtr = nullptr;
char* tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
std::string key(tablePtr);
tablePtr = strtok_r(nullptr, ",", &savePtr);
CheckError(tablePtr == nullptr, VOID_VALUE, "value is nullptr");
std::string value(tablePtr);
pCurrentCam->mCameraModuleToAiqbMap[key] = value;
tablePtr = strtok_r(nullptr, ",", &savePtr);
}
} else if (strcmp(name, "isISYSCompression") == 0) {
pCurrentCam->mISYSCompression = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "isPSACompression") == 0) {
pCurrentCam->mPSACompression = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "isOFSCompression") == 0) {
pCurrentCam->mOFSCompression = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "faceAeEnabled") == 0) {
pCurrentCam->mFaceAeEnabled = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "psysAlignWithSof") == 0) {
pCurrentCam->mPsysAlignWithSof = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "psysBundleWithAic") == 0) {
pCurrentCam->mPsysBundleWithAic = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "swProcessingAlignWithIsp") == 0) {
pCurrentCam->mSwProcessingAlignWithIsp = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "faceEngineRunningInterval") == 0) {
int val = atoi(atts[1]);
pCurrentCam->mFaceEngineRunningInterval =
val > 0 ? val : FACE_ENGINE_DEFAULT_RUNNING_INTERVAL;
} else if (strcmp(name, "faceEngineRunningIntervalNoFace") == 0) {
int val = atoi(atts[1]);
pCurrentCam->mFaceEngineRunningIntervalNoFace =
val > 0 ? val : FACE_ENGINE_DEFAULT_RUNNING_INTERVAL;
} else if (strcmp(name, "faceEngineRunningSync") == 0) {
pCurrentCam->mFaceEngineRunningSync = strcmp(atts[1], "true") == 0;
} else if (strcmp(name, "maxFaceDetectionNumber") == 0) {
int val = atoi(atts[1]);
pCurrentCam->mMaxFaceDetectionNumber =
val > 0 ? std::min(val, MAX_FACES_DETECTABLE) : MAX_FACES_DETECTABLE;
} else if (strcmp(name, "videoStreamNum") == 0) {
int val = atoi(atts[1]);
pCurrentCam->mVideoStreamNum = val > 0 ? val : DEFAULT_VIDEO_STREAM_NUM;
} else if (strcmp(name, "tnrExtraFrameNum") == 0) {
int val = atoi(atts[1]);
pCurrentCam->mTnrExtraFrameNum = val > 0 ? val : DEFAULT_TNR_EXTRA_FRAME_NUM;
} else if (strcmp(name, "tnrThresholdGain") == 0) {
float val = atof(atts[1]);
pCurrentCam->mTnrThresholdGain = val > 0 ? val : DEFAULT_TNR_THRESHOLD_GAIN;
}
}
int CameraParser::parseSupportedTuningConfig(const char *str, vector <TuningConfig> &config)
{
CheckError(str == nullptr, -1, "@%s, str is nullptr", __func__);
LOGXML("@%s, str = %s", __func__, str);
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
char *savePtr;
char *configMode = strtok_r(src, ",", &savePtr);
TuningConfig cfg;
while (configMode) {
char* tuningMode = strtok_r(nullptr, ",", &savePtr);
char* aiqb = strtok_r(nullptr, ",", &savePtr);
CheckError(configMode == nullptr || tuningMode == nullptr
|| aiqb == nullptr, -1, "@%s, wrong str %s", __func__, str);
LOGXML("@%s, configMode %s, tuningMode %s, aiqb name %s",
__func__, configMode, tuningMode, aiqb);
cfg.configMode = CameraUtils::getConfigModeByName(configMode);
cfg.tuningMode = CameraUtils::string2TuningMode(tuningMode);
cfg.aiqbName = aiqb;
config.push_back(cfg);
if (savePtr != nullptr)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
configMode = strtok_r(nullptr, ",", &savePtr);
}
return 0;
}
int CameraParser::parseLardTags(const char *str, vector <LardTagConfig> &lardTags)
{
CheckError(str == nullptr, -1, "@%s, str is nullptr", __func__);
LOGXML("@%s, str = %s", __func__, str);
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
char *savePtr;
char *tuningMode = strtok_r(src, ",", &savePtr);
LardTagConfig cfg;
while (tuningMode) {
char* cmcTag = strtok_r(nullptr, ",", &savePtr);
char* aiqTag = strtok_r(nullptr, ",", &savePtr);
char* ispTag = strtok_r(nullptr, ",", &savePtr);
char* othersTag = strtok_r(nullptr, ",", &savePtr);
cfg.tuningMode = CameraUtils::string2TuningMode(tuningMode);
cfg.cmcTag = CameraUtils::fourcc2UL(cmcTag);
cfg.aiqTag = CameraUtils::fourcc2UL(aiqTag);
cfg.ispTag = CameraUtils::fourcc2UL(ispTag);
cfg.othersTag = CameraUtils::fourcc2UL(othersTag);
CheckError(cfg.cmcTag == 0 || cfg.aiqTag == 0 || cfg.ispTag == 0
|| cfg.othersTag == 0, -1, "@%s, wrong str %s", __func__, str);
lardTags.push_back(cfg);
LOGXML("@%s, tuningMode %s, cmc %s, aiq %s, isp %s, others %s",
__func__, tuningMode, cmcTag, aiqTag, ispTag, othersTag);
if (savePtr != nullptr)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
tuningMode = strtok_r(nullptr, ",", &savePtr);
}
return 0;
}
void CameraParser::parseMediaCtlConfigElement(CameraParser *profiles, const char *name, const char **atts)
{
MediaCtlConf mc;
int idx = 0;
while (atts[idx]) {
const char *key = atts[idx];
LOGXML("%s: name: %s, value: %s", __func__, atts[idx], atts[idx + 1]);
if (strcmp(key, "id") == 0) {
mc.mcId = strtol(atts[idx + 1], nullptr, 10);
} else if (strcmp(key, "ConfigMode") == 0) {
parseXmlConvertStrings(atts[idx + 1], mc.configMode, CameraUtils::getConfigModeByName);
} else if (strcmp(key, "outputWidth") == 0) {
mc.outputWidth = strtoul(atts[idx + 1], nullptr, 10);
} else if (strcmp(key, "outputHeight") == 0) {
mc.outputHeight = strtoul(atts[idx + 1], nullptr, 10);
} else if (strcmp(key, "format") == 0) {
mc.format = CameraUtils::string2PixelCode(atts[idx + 1]);
}
idx += 2;
}
LOGXML("@%s, name:%s, atts[0]:%s, id: %d", __func__, name, atts[0], mc.mcId);
//Add a new empty MediaControl Configuration
profiles->pCurrentCam->mMediaCtlConfs.push_back(mc);
}
#define V4L2_CID_WATERMARK 0x00982901
#define V4L2_CID_WATERMARK2 0x00982902
void CameraParser::parseControlElement(CameraParser *profiles, const char *name, const char **atts)
{
McCtl ctl;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
LOGXML("@%s, name:%s", __func__, name);
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx + 1, val);
if (strcmp(key, "name") == 0) {
ctl.entityName = replaceStringInXml(profiles, val);
ctl.entity = profiles->mMC->getEntityIdByName(ctl.entityName.c_str());
} else if (strcmp(key, "ctrlId") == 0) {
if (!strcmp(val, "V4L2_CID_LINK_FREQ")) {
ctl.ctlCmd = V4L2_CID_LINK_FREQ;
} else if (!strcmp(val, "V4L2_CID_VBLANK")) {
ctl.ctlCmd = V4L2_CID_VBLANK;
} else if (!strcmp(val, "V4L2_CID_HBLANK")) {
ctl.ctlCmd = V4L2_CID_HBLANK;
} else if (!strcmp(val, "V4L2_CID_EXPOSURE")) {
ctl.ctlCmd = V4L2_CID_EXPOSURE;
} else if (!strcmp(val, "V4L2_CID_ANALOGUE_GAIN")) {
ctl.ctlCmd = V4L2_CID_ANALOGUE_GAIN;
} else if (!strcmp(val, "V4L2_CID_HFLIP")) {
ctl.ctlCmd = V4L2_CID_HFLIP;
} else if (!strcmp(val, "V4L2_CID_VFLIP")) {
ctl.ctlCmd = V4L2_CID_VFLIP;
} else if (!strcmp(val, "V4L2_CID_WATERMARK")) {
ctl.ctlCmd = V4L2_CID_WATERMARK;
} else if (!strcmp(val, "V4L2_CID_WATERMARK2")) {
ctl.ctlCmd = V4L2_CID_WATERMARK2;
} else if (!strcmp(val, "V4L2_CID_TEST_PATTERN")) {
ctl.ctlCmd = V4L2_CID_TEST_PATTERN;
} else {
LOGE("Unknow ioctl command %s", val);
ctl.ctlCmd = -1;
}
} else if (strcmp(key, "value") == 0) {
ctl.ctlValue = strtoul(val, nullptr, 10);
} else if (strcmp(key, "ctrlName") == 0) {
ctl.ctlName = val;
}
idx += 2;
}
mc.ctls.push_back(ctl);
}
void CameraParser::parseSelectionElement(CameraParser *profiles, const char *name, const char **atts)
{
McFormat sel;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
LOGXML("@%s, name:%s", __func__, name);
sel.top = -1; //top is not specified, need to be calc later.
sel.left = -1; //left is not specified, need to be calc later.
sel.width = 0; //width is not specified, need to be calc later.
sel.height = 0; //height is not specified, need to be calc later.
sel.formatType = FC_SELECTION;
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "name") == 0) {
sel.entityName = replaceStringInXml(profiles, val);
sel.entity = profiles->mMC->getEntityIdByName(sel.entityName.c_str());
} else if (strcmp(key, "pad") == 0) {
sel.pad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "target") == 0) {
if (!strcmp(val, "V4L2_SEL_TGT_COMPOSE")) {
sel.selCmd = V4L2_SEL_TGT_COMPOSE;
} else if (!strcmp(val, "V4L2_SEL_TGT_CROP")) {
sel.selCmd = V4L2_SEL_TGT_CROP;
}
} else if (strcmp(key, "top") == 0) {
sel.top = strtoul(val, nullptr, 10);
} else if (strcmp(key, "left") == 0) {
sel.left = strtoul(val, nullptr, 10);
} else if (strcmp(key, "width") == 0) {
sel.width = strtoul(val, nullptr, 10);
} else if (strcmp(key, "height") == 0) {
sel.height = strtoul(val, nullptr, 10);
}
idx += 2;
}
mc.formats.push_back(sel);
}
/**
* Store the MediaCtlConf mapping table for supportedStreamConfig by id.
* Then we can select the MediaCtlConf through this table and configured stream.
*/
void CameraParser::storeMcMappForConfig(int mcId, stream_t streamCfg)
{
//We need to insert new one if mcId isn't in mStreamToMcMap.
if (pCurrentCam->mStreamToMcMap.find(mcId) == pCurrentCam->mStreamToMcMap.end()) {
pCurrentCam->mStreamToMcMap.insert(std::pair<int, stream_array_t>(mcId, stream_array_t()));
}
stream_array_t &streamVector = pCurrentCam->mStreamToMcMap[mcId];
streamVector.push_back(streamCfg);
}
/**
* \brief Parses the string with the supported stream configurations
* a stream configuration is made of 4 necessary elements
* - Format
* - Resolution
* - Field (Interlaced field)
* - Media config ID
* we parse the string in 4 steps
* example of valid stream configuration is: V4L2_PIX_FMT_NV12,1920x1080,0,0
* the following elements are optional:
* - Max fps, for continuous streaming and high quality capture. (optional)
* example: V4L2_PIX_FMT_NV12,1920x1080,0,0,(30/15)
*
* \param src: string to be parsed
* \param configs: Stream config array needs to be filled in
*
*/
void CameraParser::parseStreamConfig(const char* src, stream_array_t& configs)
{
HAL_TRACE_CALL(1);
int mcId = -1;
char* endPtr = nullptr;
char* separatorPtr = nullptr;
int parseStep = 0;
stream_t config;
CLEAR(config);
#define NUM_ELEMENTS_NECESSARY 4
// Has optional element
#define NUM_ELEMENTS (NUM_ELEMENTS_NECESSARY + 1)
bool lastElement = false; // the last one?
do {
parseStep++;
// Get the next segement for necessary element
// Get the next segement for optional element if it exist
if (parseStep <= NUM_ELEMENTS_NECESSARY
|| (!lastElement && (*src == '('))) {
separatorPtr = (char *)strchr(src, ',');
if (separatorPtr) {
*separatorPtr = 0;
} else {
lastElement = true;
}
}
switch (parseStep) {
case 1: // Step 1: Parse format
LOGXML("stream format is %s", src);
config.format = CameraUtils::string2PixelCode(src);
CheckError(config.format == -1, VOID_VALUE, "@%s, format fails", __func__);
break;
case 2: // Step 2: Parse the resolution
config.width = strtol(src, &endPtr, 10);
CheckError(!endPtr || *endPtr != 'x', VOID_VALUE, "@%s, width fails", __func__);
src = endPtr + 1;
config.height = strtol(src, &endPtr, 10);
LOGXML("(%dx%d)", config.width, config.height);
break;
case 3: // Step 3: Parse field
config.field = strtol(src, &endPtr, 10);
LOGXML("stream field is %d", config.field);
break;
case 4: // Step 4: Parse MediaCtlConf id.
mcId = strtol(src, &endPtr, 10);
CheckError(mcId < 0, VOID_VALUE, "@%s, mcId fails", __func__);
LOGXML("the mcId for supported stream config is %d", mcId);
break;
}
if (!lastElement) {
// Move to the next element
src = separatorPtr + 1;
src = skipWhiteSpace(src);
} else if (parseStep < NUM_ELEMENTS_NECESSARY ){
LOGE("Malformed stream configuration, only finish step %d", parseStep);
return;
}
// Finish all elements for one config
if (parseStep >= NUM_ELEMENTS) {
configs.push_back(config);
storeMcMappForConfig(mcId, config);
CLEAR(config);
mcId = -1;
parseStep = 0;
LOGXML("Stream Configuration found");
if (lastElement) {
break;
}
}
} while (true);
}
void CameraParser::parseSupportedFeatures(const char* src, camera_features_list_t& features)
{
HAL_TRACE_CALL(1);
char * endPtr = nullptr;
camera_features feature = INVALID_FEATURE;
do {
endPtr = (char *)strchr(src, ',');
if (endPtr) {
*endPtr = 0;
}
if (strcmp(src, "MANUAL_EXPOSURE") == 0) {
feature = MANUAL_EXPOSURE;
} else if (strcmp(src, "MANUAL_WHITE_BALANCE") == 0) {
feature = MANUAL_WHITE_BALANCE;
} else if (strcmp(src, "IMAGE_ENHANCEMENT") == 0) {
feature = IMAGE_ENHANCEMENT;
} else if (strcmp(src, "NOISE_REDUCTION") == 0) {
feature = NOISE_REDUCTION;
} else if (strcmp(src, "SCENE_MODE") == 0) {
feature = SCENE_MODE;
} else if (strcmp(src, "WEIGHT_GRID_MODE") == 0) {
feature = WEIGHT_GRID_MODE;
} else if (strcmp(src, "PER_FRAME_CONTROL") == 0) {
feature = PER_FRAME_CONTROL;
} else if (strcmp(src, "ISP_CONTROL") == 0) {
feature = ISP_CONTROL;
} else {
feature = INVALID_FEATURE;
}
if (feature != INVALID_FEATURE) {
features.push_back(feature);
}
if (endPtr) {
src = endPtr + 1;
src = skipWhiteSpace(src);
}
} while (endPtr);
}
int CameraParser::parseSupportedVideoStabilizationMode(const char* str, camera_video_stabilization_list_t &supportedModes)
{
HAL_TRACE_CALL(1);
CheckError(str == nullptr, -1, "@%s, str is nullptr", __func__);
char *savePtr, *tablePtr;
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
camera_video_stabilization_mode_t mode = VIDEO_STABILIZATION_MODE_OFF;
tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
if (strcmp(tablePtr, "ON") == 0) {
mode = VIDEO_STABILIZATION_MODE_ON;
} else if (strcmp(tablePtr, "OFF") == 0) {
mode = VIDEO_STABILIZATION_MODE_OFF;
}
supportedModes.push_back(mode);
if (savePtr != nullptr)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
tablePtr = strtok_r(nullptr, ",", &savePtr);
}
return OK;
}
int CameraParser::parseSupportedAeMode(const char* str, vector <camera_ae_mode_t> &supportedModes)
{
HAL_TRACE_CALL(1);
CheckError(str == nullptr, -1, "@%s, str is nullptr", __func__);
char *savePtr, *tablePtr;
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
camera_ae_mode_t aeMode = AE_MODE_AUTO;
tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
if (strcmp(tablePtr, "AUTO") == 0) {
aeMode = AE_MODE_AUTO;
} else if (strcmp(tablePtr, "MANUAL") == 0) {
aeMode = AE_MODE_MANUAL;
}
supportedModes.push_back(aeMode);
if (savePtr != nullptr)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
tablePtr = strtok_r(nullptr, ",", &savePtr);
}
return OK;
}
int CameraParser::parseSupportedAfMode(const char* str, vector <camera_af_mode_t> &supportedModes)
{
HAL_TRACE_CALL(1);
CheckError(str == NULL, -1, "@%s, str is NULL", __func__);
char *savePtr, *tablePtr;
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
camera_af_mode_t afMode = AF_MODE_AUTO;
tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
if (strcmp(tablePtr, "AUTO") == 0) {
afMode = AF_MODE_AUTO;
} else if (strcmp(tablePtr, "MACRO") == 0) {
afMode = AF_MODE_MACRO;
} else if (strcmp(tablePtr, "CONTINUOUS_VIDEO") == 0) {
afMode = AF_MODE_CONTINUOUS_VIDEO;
} else if (strcmp(tablePtr, "CONTINUOUS_PICTURE") == 0) {
afMode = AF_MODE_CONTINUOUS_PICTURE;
} else if (strcmp(tablePtr, "OFF") == 0) {
afMode = AF_MODE_OFF;
}
supportedModes.push_back(afMode);
if (savePtr != NULL)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
tablePtr = strtok_r(NULL, ",", &savePtr);
}
return OK;
}
int CameraParser::parseSupportedAntibandingMode(const char* str, vector <camera_antibanding_mode_t> &supportedModes)
{
HAL_TRACE_CALL(1);
CheckError(str == nullptr, -1, "@%s, str is nullptr", __func__);
char *savePtr, *tablePtr;
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
camera_antibanding_mode_t antibandingMode = ANTIBANDING_MODE_OFF;
tablePtr = strtok_r(src, ",", &savePtr);
while (tablePtr) {
if (strcmp(tablePtr, "AUTO") == 0) {
antibandingMode = ANTIBANDING_MODE_AUTO;
} else if (strcmp(tablePtr, "50Hz") == 0) {
antibandingMode = ANTIBANDING_MODE_50HZ;
} else if (strcmp(tablePtr, "60Hz") == 0) {
antibandingMode = ANTIBANDING_MODE_60HZ;
} else if (strcmp(tablePtr, "OFF") == 0) {
antibandingMode = ANTIBANDING_MODE_OFF;
}
supportedModes.push_back(antibandingMode);
if (savePtr != nullptr)
savePtr = const_cast<char*>(skipWhiteSpace(savePtr));
tablePtr = strtok_r(nullptr, ",", &savePtr);
}
return OK;
}
int CameraParser::parseSupportedAeParamRange(const char* src, vector<int>& scenes,
vector<float>& minValues, vector<float>& maxValues)
{
HAL_TRACE_CALL(1);
char* srcDup = strdup(src);
CheckError((srcDup == nullptr), NO_MEMORY, "Create a copy of source string failed.");
char* srcTmp = srcDup;
char* endPtr = nullptr;
while ((endPtr = (char *)strchr(srcTmp, ','))) {
if (endPtr) *endPtr = 0;
camera_scene_mode_t scene = CameraUtils::getSceneModeByName(srcTmp);
scenes.push_back(scene);
if (endPtr) {
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
}
float min = strtof(srcTmp, &endPtr);
minValues.push_back(min);
if (endPtr == nullptr || *endPtr != ',') {
LOGE("Malformed ET range in exposure time range configuration");
free(srcDup);
return UNKNOWN_ERROR;
}
srcTmp = endPtr + 1;
float max = strtof(srcTmp, &endPtr);
maxValues.push_back(max);
if (endPtr) {
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
}
}
free(srcDup);
return OK;
}
void CameraParser::parseFormatElement(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s", __func__, name);
McFormat fmt;
fmt.type = RESOLUTION_TARGET;
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "name") == 0) {
fmt.entityName = replaceStringInXml(profiles, val);
fmt.entity = profiles->mMC->getEntityIdByName(fmt.entityName.c_str());
} else if (strcmp(key, "pad") == 0) {
fmt.pad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "stream") == 0) {
fmt.stream = strtoul(val, nullptr, 10);
} else if (strcmp(key, "type") == 0) {
if (strcmp(val, "RESOLUTION_MAX") == 0) {
fmt.type = RESOLUTION_MAX;
} else if (strcmp(val, "RESOLUTION_COMPOSE") == 0) {
fmt.type = RESOLUTION_COMPOSE;
} else if (strcmp(val, "RESOLUTION_CROP") == 0) {
fmt.type = RESOLUTION_CROP;
} else if (strcmp(val, "RESOLUTION_TARGET") == 0) {
fmt.type = RESOLUTION_TARGET;
} else {
LOGE("Parse format type failed. type = %s", val);
return;
}
} else if (strcmp(key, "width") == 0) {
fmt.width = strtoul(val, nullptr, 10);
} else if (strcmp(key, "height") == 0) {
fmt.height = strtoul(val, nullptr, 10);
} else if (strcmp(key, "format") == 0) {
fmt.pixelCode = CameraUtils::string2PixelCode(val);
}
idx += 2;
}
fmt.formatType = FC_FORMAT;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
mc.formats.push_back(fmt);
}
void CameraParser::parseLinkElement(CameraParser *profiles, const char *name, const char **atts)
{
McLink link;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
LOGXML("@%s, name:%s", __func__, name);
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "srcName") == 0) {
link.srcEntityName = replaceStringInXml(profiles, val);
link.srcEntity = profiles->mMC->getEntityIdByName(link.srcEntityName.c_str());
} else if (strcmp(key, "srcPad") == 0) {
link.srcPad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "sinkName") == 0) {
link.sinkEntityName = replaceStringInXml(profiles, val);
link.sinkEntity = profiles->mMC->getEntityIdByName(link.sinkEntityName.c_str());
} else if (strcmp(key, "sinkPad") == 0) {
link.sinkPad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "enable") == 0) {
link.enable = strcmp(val, "true") == 0;
}
idx += 2;
}
mc.links.push_back(link);
}
void CameraParser::parseRouteElement(CameraParser *profiles, const char *name, const char **atts)
{
McRoute route;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
LOGXML("@%s, name:%s", __func__, name);
route.flag = MEDIA_LNK_FL_ENABLED;
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "name") == 0) {
route.entityName = replaceStringInXml(profiles, val);
route.entity = profiles->mMC->getEntityIdByName(route.entityName.c_str());
} else if (strcmp(key, "srcPad") == 0) {
route.srcPad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "sinkPad") == 0) {
route.sinkPad = strtoul(val, nullptr, 10);
} else if (strcmp(key, "srcStream") == 0) {
route.srcStream = strtoul(val, nullptr, 10);
} else if (strcmp(key, "sinkStream") == 0) {
route.sinkStream = strtoul(val, nullptr, 10);
} else if (strcmp(key, "flag") == 0) {
route.flag = strtoul(val, nullptr, 10);
}
idx += 2;
}
mc.routes.push_back(route);
}
void CameraParser::parseVideoElement(CameraParser *profiles, const char * /*name*/, const char **atts)
{
McVideoNode videoNode;
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
videoNode.name = replaceStringInXml(profiles, atts[1]);
videoNode.videoNodeType = GetNodeType(atts[3]);
LOGXML("@%s, name:%s, videoNodeType:%d", __func__, videoNode.name.c_str(), videoNode.videoNodeType);
mc.videoNodes.push_back(videoNode);
}
// MediaCtl output tag xml parsing code for the field like:
// <output port="main" width="1920" height="1088" format="V4L2_PIX_FMT_YUYV420_V32"/>
// <output port="second" width="3264" height="2448" format="V4L2_PIX_FMT_SGRBG12V32"/>
void CameraParser::parseOutputElement(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s", __func__, name);
McOutput output;
int idx = 0;
while (atts[idx]) {
const char* key = atts[idx];
const char* val = atts[idx + 1];
LOGXML("@%s, name:%s, atts[%d]:%s, atts[%d]:%s", __func__, name, idx, key, idx+1, val);
if (strcmp(key, "port") == 0) {
if (strcmp(val, "main") == 0)
output.port = MAIN_PORT;
else if (strcmp(val, "second") == 0)
output.port = SECOND_PORT;
else if (strcmp(val, "third") == 0)
output.port = THIRD_PORT;
else if (strcmp(val, "forth") == 0)
output.port = FORTH_PORT;
else
output.port = INVALID_PORT;
} else if (strcmp(key, "width") == 0) {
output.width = strtoul(val, nullptr, 10);
} else if (strcmp(key, "height") == 0) {
output.height = strtoul(val, nullptr, 10);
} else if (strcmp(key, "format") == 0) {
output.v4l2Format = CameraUtils::string2PixelCode(val);
}
idx += 2;
}
LOGXML("@%s, port:%d, output size:%dx%d, v4l2Format:%x", __func__, output.port,
output.width, output.height, output.v4l2Format);
MediaCtlConf &mc = profiles->pCurrentCam->mMediaCtlConfs.back();
mc.outputs.push_back(output);
}
void CameraParser::parseMultiExpRange(const char* src)
{
ExpRange* range = nullptr;
MultiExpRange multiRange;
MultiExpRange* pCurrRange = nullptr;
pCurrentCam->mMultiExpRanges.clear();
static const int MULTI_EXPOSURE_TAG_SHS1 = 0;
static const int MULTI_EXPOSURE_TAG_RHS1 = 1;
static const int MULTI_EXPOSURE_TAG_SHS2 = 2;
static const int MULTI_EXPOSURE_TAG_RHS2 = 3;
static const int MULTI_EXPOSURE_TAG_SHS3 = 4;
string srcDup = src;
CheckError((srcDup.c_str() == nullptr), VOID_VALUE, "Create a copy of source string failed.");
const char* srcTmp = srcDup.c_str();
char* endPtr = nullptr;
int tag = -1;
while ((endPtr = (char *)strchr(srcTmp, ','))) {
*endPtr = 0;
if (strcmp(srcTmp, "SHS1") == 0) {
tag = MULTI_EXPOSURE_TAG_SHS1;
} else if (strcmp(srcTmp, "RHS1") == 0) {
tag = MULTI_EXPOSURE_TAG_RHS1;
} else if (strcmp(srcTmp, "SHS2") == 0) {
tag = MULTI_EXPOSURE_TAG_SHS2;
} else if (strcmp(srcTmp, "RHS2") == 0) {
tag = MULTI_EXPOSURE_TAG_RHS2;
} else if (strcmp(srcTmp, "SHS3") == 0) {
tag = MULTI_EXPOSURE_TAG_SHS3;
} else {
LOGE("Malformed tag for multi-exposure range configuration");
return;
}
if (endPtr) {
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
}
CLEAR(multiRange);
multiRange.Resolution.width = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed resolution for multi-exposure range configuration");
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
multiRange.Resolution.height = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed resolution for multi-exposure range configuration");
pCurrRange = nullptr;
for (unsigned int i = 0; i < pCurrentCam->mMultiExpRanges.size(); i++) {
if (pCurrentCam->mMultiExpRanges[i].Resolution.width == multiRange.Resolution.width &&
pCurrentCam->mMultiExpRanges[i].Resolution.height == multiRange.Resolution.height) {
pCurrRange = &(pCurrentCam->mMultiExpRanges[i]);
break;
}
}
if (pCurrRange) {
switch (tag) {
case MULTI_EXPOSURE_TAG_SHS1:
range = &pCurrRange->SHS1;
break;
case MULTI_EXPOSURE_TAG_RHS1:
range = &pCurrRange->RHS1;
break;
case MULTI_EXPOSURE_TAG_SHS2:
range = &pCurrRange->SHS2;
break;
case MULTI_EXPOSURE_TAG_RHS2:
range = &pCurrRange->RHS2;
break;
case MULTI_EXPOSURE_TAG_SHS3:
range = &pCurrRange->SHS3;
break;
default:
LOGE("Wrong tag for multi-exposure range configuration");
return;
}
} else {
switch (tag) {
case MULTI_EXPOSURE_TAG_SHS1:
range = &multiRange.SHS1;
break;
case MULTI_EXPOSURE_TAG_RHS1:
range = &multiRange.RHS1;
break;
case MULTI_EXPOSURE_TAG_SHS2:
range = &multiRange.SHS2;
break;
case MULTI_EXPOSURE_TAG_RHS2:
range = &multiRange.RHS2;
break;
case MULTI_EXPOSURE_TAG_SHS3:
range = &multiRange.SHS3;
break;
default:
LOGE("Wrong tag for multi-exposure range configuration");
return;
}
}
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
range->min = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed range for multi-exposure range configuration");
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
range->max = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed range for multi-exposure range configuration");
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
range->step = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed range for multi-exposure range configuration");
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
range->lowerBound = strtol(srcTmp, &endPtr, 10);
CheckError((endPtr == nullptr || *endPtr != ','), VOID_VALUE, "Malformed range for multi-exposure range configuration");
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
range->upperBound = strtol(srcTmp, &endPtr, 10);
if (endPtr) {
srcTmp = endPtr + 1;
srcTmp = const_cast<char*>(skipWhiteSpace(srcTmp));
}
if (!pCurrRange) {
pCurrentCam->mMultiExpRanges.push_back(multiRange);
}
}
}
int CameraParser::parsePair(const char *str, int *first, int *second, char delim, char **endptr)
{
// Find the first integer.
char *end;
int w = (int)strtol(str, &end, 10);
// If a delimeter does not immediately follow, give up.
if (*end != delim) {
LOGE("Cannot find delimeter (%c) in str=%s", delim, str);
return -1;
}
// Find the second integer, immediately after the delimeter.
int h = (int)strtol(end+1, &end, 10);
*first = w;
*second = h;
if (endptr) {
*endptr = end;
}
return 0;
}
void CameraParser::parseSizesList(const char *sizesStr, vector <camera_resolution_t> &sizes)
{
if (sizesStr == 0) {
return;
}
char *sizeStartPtr = (char *)sizesStr;
while (true) {
camera_resolution_t r;
int success = parsePair(sizeStartPtr, &r.width, &r.height, 'x',
&sizeStartPtr);
if (success == -1 || (*sizeStartPtr != ',' && *sizeStartPtr != '\0')) {
LOGE("Picture sizes string \"%s\" contains invalid character.", sizesStr);
return;
}
if (r.width > 0 && r.height > 0)
sizes.push_back(r);
if (*sizeStartPtr == '\0') {
return;
}
sizeStartPtr++;
}
}
/*
* The pls output to user requirement mapping table
*
* first: user requirement, second: psl output
* eg: <pslOutputForRotation value="3264x2448@1200x1600"/>
*/
void CameraParser::parseOutputMap(const char *str, vector<UserToPslOutputMap> &outputMap)
{
char *srcDup = strdup(str);
CheckError((srcDup == nullptr), VOID_VALUE, "Create a copy of source string failed.");
char *srcTmp = srcDup;
char *endPtr = nullptr;
do {
endPtr = (char *)strchr(srcTmp, ',');
if (endPtr) {
*endPtr = 0;
}
char *tmpPtr = (char *)strchr(srcTmp, '@');
if (tmpPtr) {
*tmpPtr = 0;
}
UserToPslOutputMap map;
parsePair(srcTmp, &(map.User).width, &(map.User).height, 'x');
if (tmpPtr) {
srcTmp = tmpPtr + 1;
srcTmp = (char*)skipWhiteSpace(srcTmp);
}
parsePair(srcTmp, &(map.Psl).width, &(map.Psl).height, 'x');
outputMap.push_back(map);
if (endPtr) {
srcTmp = endPtr + 1;
srcTmp = (char*)skipWhiteSpace(srcTmp);
}
} while (endPtr);
free(srcDup);
}
int CameraParser::getSupportedFormat(const char* str, vector <int>& supportedFormat)
{
if (str == nullptr) {
LOGE("the str is nullptr");
return -1;
}
LOGXML("@%s, str:%s", __func__, str);
int sz = strlen(str);
char src[sz + 1];
MEMCPY_S(src, sz, str, sz);
src[sz] = '\0';
char* savePtr;
char* fmt = strtok_r(src, ",", &savePtr);
while (fmt) {
int actual = CameraUtils::string2PixelCode(fmt);
if (actual != -1) {
supportedFormat.push_back(actual);
LOGXML("@%s, add format:%d", __func__, actual);
}
fmt = strtok_r(nullptr, ",", &savePtr);
}
return 0;
}
/**
* This function will handle all the MediaCtlCfg related elements.
*
* It will be called in the function startElement
*
* \param profiles: the pointer of the CameraParser.
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraParser::handleMediaCtlCfg(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s, atts[0]:%s, profiles->mCurrentSensor:%d", __func__, name, atts[0], profiles->mCurrentSensor);
if (strcmp(name, "MediaCtlConfig") == 0) {
parseMediaCtlConfigElement(profiles, name, atts);
} else if (strcmp(name, "link") == 0) {
parseLinkElement(profiles, name, atts);
} else if (strcmp(name, "route") == 0) {
parseRouteElement(profiles, name, atts);
} else if (strcmp(name, "control") == 0) {
parseControlElement(profiles, name, atts);
} else if (strcmp(name, "selection") == 0) {
parseSelectionElement(profiles, name, atts);
} else if (strcmp(name, "format") == 0) {
parseFormatElement(profiles, name, atts);
} else if (strcmp(name, "videonode") == 0) {
parseVideoElement(profiles, name, atts);
} else if (strcmp(name, "output") == 0) {
parseOutputElement(profiles, name, atts);
}
}
/**
* This function will handle all the StaticMetadata related elements.
*
* It will be called in the function startElement
*
* \param profiles: the pointer of the CameraParser.
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void CameraParser::handleStaticMetaData(CameraParser *profiles, const char *name, const char **atts)
{
LOGXML("@%s, name:%s, atts[0]:%s, profiles->mCurrentSensor:%d", __func__, name, atts[0], profiles->mCurrentSensor);
if (strcmp(name, "supportedStreamConfig") == 0) {
stream_array_t configsArray;
parseStreamConfig(atts[1], configsArray);
const int STREAM_MEMBER_NUM = sizeof(stream_t) / sizeof(int);
int dataSize = configsArray.size() * STREAM_MEMBER_NUM;
int configs[dataSize];
CLEAR(configs);
for (size_t i = 0; i < configsArray.size(); i++) {
LOGXML("@%s, stream config info: format=%s (%dx%d) field=%d type=%d", __func__,
CameraUtils::format2string(configsArray[i].format).c_str(),
configsArray[i].width, configsArray[i].height,
configsArray[i].field, configsArray[i].streamType);
MEMCPY_S(&configs[i * STREAM_MEMBER_NUM], sizeof(stream_t),
&configsArray[i], sizeof(stream_t));
}
mMetadata.update(INTEL_INFO_AVAILABLE_CONFIGURATIONS, configs, dataSize);
} else if (strcmp(name, "fpsRange") == 0) {
vector<double> rangeArray;
parseXmlConvertStrings(atts[1], rangeArray, atof);
float fpsRange[rangeArray.size()];
CLEAR(fpsRange);
for (size_t i = 0; i < rangeArray.size(); i++){
fpsRange[i] = static_cast<float>(rangeArray[i]);
}
LOGXML("@%s, supported fps range size: %zu", __func__, rangeArray.size());
mMetadata.update(CAMERA_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRange, ARRAY_SIZE(fpsRange));
} else if (strcmp(name, "evRange") == 0) {
vector<int> rangeArray;
parseXmlConvertStrings(atts[1], rangeArray, atoi);
int evRange[rangeArray.size()];
CLEAR(evRange);
for (size_t i = 0; i < rangeArray.size(); i++) {
evRange[i] = rangeArray[i];
}
LOGXML("@%s, supported ev range size: %zu", __func__, rangeArray.size());
mMetadata.update(CAMERA_AE_COMPENSATION_RANGE, evRange, ARRAY_SIZE(evRange));
} else if (strcmp(name, "evStep") == 0) {
vector<int> rationalType;
int ret = parseXmlConvertStrings(atts[1], rationalType, atoi);
CheckError((ret != OK), VOID_VALUE, "Parse evStep failed");
icamera_metadata_rational_t evStep = {rationalType[0], rationalType[1]};
LOGXML("@%s, the numerator: %d, denominator: %d", __func__, evStep.numerator, evStep.denominator);
mMetadata.update(CAMERA_AE_COMPENSATION_STEP, &evStep, 1);
} else if (strcmp(name, "supportedFeatures") == 0) {
camera_features_list_t supportedFeatures;
parseSupportedFeatures(atts[1], supportedFeatures);
int numberOfFeatures = supportedFeatures.size();
uint8_t features[numberOfFeatures];
CLEAR(features);
for (int i = 0; i < numberOfFeatures; i++) {
features[i] = supportedFeatures[i];
}
mMetadata.update(INTEL_INFO_AVAILABLE_FEATURES, features, numberOfFeatures);
} else if (strcmp(name, "supportedAeExposureTimeRange") == 0) {
vector<int> scenes;
vector<float> minValues, maxValues;
int ret = parseSupportedAeParamRange(atts[1], scenes, minValues, maxValues);
CheckError((ret != OK), VOID_VALUE, "Parse AE eExposure time range failed");
const int MEMBER_COUNT = 3;
const int dataSize = scenes.size() * MEMBER_COUNT;
int rangeData[dataSize];
CLEAR(rangeData);
for (size_t i = 0; i < scenes.size(); i++) {
LOGXML("@%s, scene mode:%d supported exposure time range (%f-%f)", __func__,
scenes[i], minValues[i], maxValues[i]);
rangeData[i * MEMBER_COUNT] = scenes[i];
rangeData[i * MEMBER_COUNT + 1] = (int)minValues[i];
rangeData[i * MEMBER_COUNT + 2] = (int)maxValues[i];
}
mMetadata.update(INTEL_INFO_AE_EXPOSURE_TIME_RANGE, rangeData, dataSize);
} else if (strcmp(name, "supportedAeGainRange") == 0) {
vector<int> scenes;
vector<float> minValues, maxValues;
int ret = parseSupportedAeParamRange(atts[1], scenes, minValues, maxValues);
CheckError((ret != OK), VOID_VALUE, "Parse AE gain range failed");
const int MEMBER_COUNT = 3;
const int dataSize = scenes.size() * MEMBER_COUNT;
int rangeData[dataSize];
CLEAR(rangeData);
for (size_t i = 0; i < scenes.size(); i++) {
LOGXML("@%s, scene mode:%d supported gain range (%f-%f)", __func__,
scenes[i], minValues[i], maxValues[i]);
rangeData[i * MEMBER_COUNT] = scenes[i];
// Since we use int to store float, before storing it we multiply min and max by 100.
rangeData[i * MEMBER_COUNT + 1] = (int)(minValues[i] * 100);
rangeData[i * MEMBER_COUNT + 2] = (int)(maxValues[i] * 100);
}
mMetadata.update(INTEL_INFO_AE_GAIN_RANGE, rangeData, dataSize);
} else if (strcmp(name, "supportedVideoStabilizationModes") == 0) {
camera_video_stabilization_list_t supportedMode;
parseSupportedVideoStabilizationMode(atts[1], supportedMode);
uint8_t modes[supportedMode.size()];
CLEAR(modes);
for(size_t i = 0; i < supportedMode.size(); i++) {
modes[i] = supportedMode[i];
}
mMetadata.update(CAMERA_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES, modes, supportedMode.size());
} else if (strcmp(name, "supportedAeMode") == 0) {
vector <camera_ae_mode_t> supportedAeMode;
parseSupportedAeMode(atts[1], supportedAeMode);
uint8_t aeModes[supportedAeMode.size()];
CLEAR(aeModes);
for (size_t i = 0; i < supportedAeMode.size(); i++) {
aeModes[i] = supportedAeMode[i];
}
mMetadata.update(CAMERA_AE_AVAILABLE_MODES, aeModes, supportedAeMode.size());
} else if (strcmp(name, "supportedAwbMode") == 0) {
vector <camera_awb_mode_t> supportedAwbMode;
parseXmlConvertStrings(atts[1], supportedAwbMode, CameraUtils::getAwbModeByName);
uint8_t awbModes[supportedAwbMode.size()];
CLEAR(awbModes);
for (size_t i = 0; i < supportedAwbMode.size(); i++) {
awbModes[i] = supportedAwbMode[i];
}
mMetadata.update(CAMERA_AWB_AVAILABLE_MODES, awbModes, supportedAwbMode.size());
} else if (strcmp(name, "supportedSceneMode") == 0) {
vector <camera_scene_mode_t> supportedSceneMode;
parseXmlConvertStrings(atts[1], supportedSceneMode, CameraUtils::getSceneModeByName);
uint8_t sceneModes[supportedSceneMode.size()];
CLEAR(sceneModes);
for (size_t i = 0; i < supportedSceneMode.size(); i++) {
sceneModes[i] = supportedSceneMode[i];
}
mMetadata.update(CAMERA_CONTROL_AVAILABLE_SCENE_MODES, sceneModes, supportedSceneMode.size());
} else if (strcmp(name, "supportedAfMode") == 0) {
vector <camera_af_mode_t> supportedAfMode;
parseSupportedAfMode(atts[1], supportedAfMode);
uint8_t afModes[supportedAfMode.size()];
CLEAR(afModes);
for (size_t i = 0; i < supportedAfMode.size(); i++) {
afModes[i] = supportedAfMode[i];
}
mMetadata.update(CAMERA_AF_AVAILABLE_MODES, afModes, supportedAfMode.size());
} else if (strcmp(name, "supportedAntibandingMode") == 0) {
vector <camera_antibanding_mode_t> supportedAntibandingMode;
parseSupportedAntibandingMode(atts[1], supportedAntibandingMode);
uint8_t antibandingModes[supportedAntibandingMode.size()];
CLEAR(antibandingModes);
for (size_t i = 0; i < supportedAntibandingMode.size(); i++) {
antibandingModes[i] = supportedAntibandingMode[i];
}
mMetadata.update(CAMERA_AE_AVAILABLE_ANTIBANDING_MODES, antibandingModes, supportedAntibandingMode.size());
} else if (strcmp(name, "sensorMountType") == 0) {
uint8_t mountType = WALL_MOUNTED;
if (strcmp(atts[1], "CEILING_MOUNTED") == 0)
mountType = CEILING_MOUNTED;
mMetadata.update(INTEL_INFO_SENSOR_MOUNT_TYPE, &mountType, 1);
LOGXML("@%s, sensor mount type: %d", __func__, mountType);
} else if (strcmp(name, "StaticMetadata") != 0) { // Make sure it doesn't reach the end of StaticMetadata.
handleGenericStaticMetaData(name, atts[1]);
}
}
/**
* \brief Parses string for generic static metadata and save them.
*
* \param name: the element's name.
* \param src: the element's value, only include data and separator 'x' or ','.
*/
void CameraParser::handleGenericStaticMetaData(const char *name, const char *src)
{
uint32_t tag = -1;
if (mGenericStaticMetadataToTag.find(name) != mGenericStaticMetadataToTag.end()) {
tag = mGenericStaticMetadataToTag[name];
}
int tagType = get_icamera_metadata_tag_type(tag);
if (tagType == -1) {
LOGW("Unsupported metadata %s", name);
return;
}
union {
uint8_t* u8;
int32_t* i32;
int64_t* i64;
float* f;
double* d;
icamera_metadata_rational_t* r;
} data;
data.u8 = (unsigned char *)mMetadataCache;
int index = 0;
int maxIndex = mMetadataCacheSize / sizeof(double); // worst case
char * endPtr = nullptr;
do {
switch (tagType) {
case ICAMERA_TYPE_BYTE:
data.u8[index]= (char)strtol(src, &endPtr, 10);
LOGXML(" - %d -", data.u8[index]);
break;
case ICAMERA_TYPE_INT32:
case ICAMERA_TYPE_RATIONAL:
data.i32[index]= strtol(src, &endPtr, 10);
LOGXML(" - %d -", data.i32[index]);
break;
case ICAMERA_TYPE_INT64:
data.i64[index]= strtol(src, &endPtr, 10);
LOGXML(" - %ld -", data.i64[index]);
break;
case ICAMERA_TYPE_FLOAT:
data.f[index]= strtof(src, &endPtr);
LOGXML(" - %8.3f -", data.f[index]);
break;
case ICAMERA_TYPE_DOUBLE:
data.d[index]= strtof(src, &endPtr);
LOGXML(" - %8.3f -", data.d[index]);
break;
}
index++;
if (endPtr != nullptr && (*endPtr == 'x' || *endPtr == ',')) {
src = endPtr + 1;
} else {
break;
}
} while (index < maxIndex);
switch (tagType) {
case ICAMERA_TYPE_BYTE:
mMetadata.update(tag, data.u8, index);
break;
case ICAMERA_TYPE_INT32:
mMetadata.update(tag, data.i32, index);
break;
case ICAMERA_TYPE_INT64:
mMetadata.update(tag, data.i64, index);
break;
case ICAMERA_TYPE_FLOAT:
mMetadata.update(tag, data.f, index);
break;
case ICAMERA_TYPE_DOUBLE:
mMetadata.update(tag, data.d, index);
break;
case ICAMERA_TYPE_RATIONAL:
mMetadata.update(tag, data.r, index / 2);
break;
}
}
/**
* 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 CameraParser::startParseElement(void *userData, const char *name, const char **atts)
{
CameraParser *profiles = reinterpret_cast<CameraParser*>(userData);
if (profiles->mCurrentDataField == FIELD_INVALID) {
profiles->checkField(profiles, name, atts);
return;
}
switch (profiles->mCurrentDataField) {
case FIELD_SENSOR:
if (strcmp(name, "MediaCtlConfig") == 0) {
profiles->mInMediaCtlCfg = true;
LOGXML("@%s %s, mInMediaCtlCfg is set to true", __func__, name);
} else if (strcmp(name, "StaticMetadata") == 0) {
profiles->mInStaticMetadata = true;
LOGXML("@%s %s, mInStaticMetadata is set to true", __func__, name);
}
if (profiles->mInMediaCtlCfg) {
// The MediaCtlCfg belongs to the sensor segments
profiles->handleMediaCtlCfg(profiles, name, atts);
} else if (profiles->mInStaticMetadata) {
// The StaticMetadata belongs to the sensor segments
profiles->handleStaticMetaData(profiles, name, atts);
} else {
profiles->handleSensor(profiles, name, atts);
}
break;
case FIELD_COMMON:
profiles->handleCommon(profiles, name, atts);
break;
default:
LOGE("@%s, line:%d, go to default handling", __func__, __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 CameraParser::endParseElement(void *userData, const char *name)
{
LOGXML("@%s %s", __func__, name);
CameraParser *profiles = reinterpret_cast<CameraParser*>(userData);
if (strcmp(name, "Sensor") == 0) {
profiles->mCurrentDataField = FIELD_INVALID;
if (profiles->pCurrentCam) {
LOGXML("@%s: Add camera id %d (%s)", __func__, profiles->mCurrentSensor,
profiles->pCurrentCam->sensorName.c_str());
if (profiles->pCurrentCam->mLensName.empty() &&
profiles->pCurrentCam->sensorName.find("-wf") != string::npos) {
int ret = profiles->mMC->getLensName(&profiles->pCurrentCam->mLensName);
if (ret != OK) {
LOGXML("@%s, Failed to getLensName", __func__);
}
}
// Merge the content of mMetadata into mCapability.
ParameterHelper::merge(profiles->mMetadata, &profiles->pCurrentCam->mCapability);
profiles->mMetadata.clear();
// For non-extended camera, it should be in order by mCurrentSensor
profiles->mStaticCfg->mCameras.insert(profiles->mStaticCfg->mCameras.begin() +
profiles->mCurrentSensor, *(profiles->pCurrentCam));
delete profiles->pCurrentCam;
profiles->pCurrentCam = nullptr;
}
}
if (strcmp(name, "MediaCtlConfig") == 0) {
LOGXML("@%s %s, mInMediaCtlCfg is set to false", __func__, name);
profiles->mInMediaCtlCfg = false;
}
if (strcmp(name, "StaticMetadata") == 0) {
LOGXML("@%s %s, mInStaticMetadata is set to false", __func__, name);
profiles->mInStaticMetadata = false;
}
if (strcmp(name, "Common") == 0)
profiles->mCurrentDataField = FIELD_INVALID;
}
/**
* Get available sensors.
*
* The function will read libcamhal_profile.xml, and parse out all of sensors.
* Then those sensors will be checked if it exists in mediaEntity, if it exists,
* we put it in availableSensors.
* In libcamhal_profile.xml it should have the following requirements:
* 1. <availableSensors value="ov8856-wf-2,ov2740-uf-0,ov2740-wf-2"/>
* The value is "'camera name'-wf/uf-'CSI port number'".
* For example: camera name is "ov8856". Sensor's sink entity name is
* "Intel IPU6 CSI-2 2" and it is word facing. The value is ov8856-wf-2.
* 2. <platform value="IPU6"/> the platform value must be uppercase letter.
*
*/
std::vector<std::string> CameraParser::getAvailableSensors(const std::string &ipuName,
const std::vector<std::string> &sensorsList)
{
LOGXML("@%s, ipuName:%s", __func__, ipuName.c_str());
/* if the string doesn't contain -wf- or -uf-, it needn't be parsed */
if ((sensorsList[0].find("-wf-") == string::npos) &&
(sensorsList[0].find("-uf-") == string::npos)) {
return sensorsList;
}
// sensor's sink entity name prefix:Intel IPU6 CSI-2 2
std::string sensorSinkName = "Intel ";
sensorSinkName.append(ipuName);
sensorSinkName.append(" CSI-2 ");
std::vector<string> availableSensors;
for (auto& sensor : sensorsList) {
std::string srcSensor = sensor;
std::string portNum = srcSensor.substr(srcSensor.find_last_of('-') + 1);
std::string sensorSinkNameTmp = sensorSinkName;
sensorSinkNameTmp.append(portNum);
std::string sensorName = srcSensor.substr(0, srcSensor.find_first_of('-'));
bool ret = mMC->checkAvailableSensor(sensorName, sensorSinkNameTmp);
if (ret) {
std::string sensorNameTmp = srcSensor.substr(0, srcSensor.find_last_of('-'));
availableSensors.push_back(sensorNameTmp);
mAvailableSensor[sensorNameTmp] = sensorSinkNameTmp;
LOGXML("@%s, The availabel sensor name:%s, sensorSinkNameTmp:%s",
__func__, sensorNameTmp.c_str(), sensorSinkNameTmp.c_str());
}
}
return availableSensors;
}
/**
* 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 CameraParser class.
*
*/
void CameraParser::getSensorDataFromXmlFile(void)
{
LOGXML("@%s", __func__);
// According to sensor name to get sensor data
LOGXML("The kinds of sensor is %zu", mStaticCfg->mCommonConfig.availableSensors.size());
vector<string> allSensors = getAvailableSensors(mStaticCfg->mCommonConfig.ipuName,
mStaticCfg->mCommonConfig.availableSensors);
if (allSensors.size() == 0) {
LOGW("The style of libcamhal_profile is too old, please switch it as soon as possible !!!");
return;
}
for (auto sensor : allSensors) {
string sensorName = "sensors/";
sensorName.append(sensor);
sensorName.append(".xml");
int ret = getDataFromXmlFile(sensorName);
CheckError(ret != OK, VOID_VALUE, "Failed to get sensor profile data frome %s", sensorName.c_str());
}
}
void CameraParser::dumpSensorInfo(void)
{
LOGXML("@%s, line%d, for sensors settings==================", __func__, __LINE__);
LOGXML("@%s, line%d, sensor number:%d", __func__, __LINE__, getSensorNum());
for (unsigned i = 0; i < getSensorNum(); i++) {
LOGXML("@%s, line%d, i:%d", __func__, __LINE__, i);
LOGXML("@%s, line%d, mCameras[%d].sensorName:%s", __func__, __LINE__, i, mStaticCfg->mCameras[i].sensorName.c_str());
LOGXML("@%s, line%d, mCameras[%d].mISysFourcc:%d", __func__, __LINE__, i, mStaticCfg->mCameras[i].mISysFourcc);
stream_array_t supportedConfigs;
mStaticCfg->mCameras[i].mCapability.getSupportedStreamConfig(supportedConfigs);
for (size_t j = 0; j < supportedConfigs.size(); j++) {
LOGXML("@%s, line%d, mCameras[%d]: format:%d size(%dx%d) field:%d", __func__, __LINE__,
i, supportedConfigs[j].format, supportedConfigs[j].width,
supportedConfigs[j].height, supportedConfigs[j].field);
}
for (unsigned j = 0; j < mStaticCfg->mCameras[i].mSupportedISysFormat.size(); j++) {
LOGXML("@%s, line%d, mCameras[%d].mSupportedISysFormat:%d", __func__, __LINE__, i, mStaticCfg->mCameras[i].mSupportedISysFormat[j]);
}
// dump the media controller mapping table for supportedStreamConfig
LOGXML("The media controller mapping table size: %zu", mStaticCfg->mCameras[i].mStreamToMcMap.size());
for (auto& pool : mStaticCfg->mCameras[i].mStreamToMcMap) {
int mcId = pool.first;
stream_array_t &mcMapVector = pool.second;
LOGXML("mcId: %d, the supportedStreamConfig vector size: %zu", mcId, mcMapVector.size());
}
// dump the media controller information
LOGXML("============Format Configuration==================");
for (unsigned j = 0; j < mStaticCfg->mCameras[i].mMediaCtlConfs.size(); j++) {
const MediaCtlConf* mc = &mStaticCfg->mCameras[i].mMediaCtlConfs[j];
for (unsigned k = 0; k < mc->links.size(); k++) {
const McLink* link = &mc->links[k];
LOGXML(" link src %s [%d:%d] ==> %s [%d:%d] enable %d", link->srcEntityName.c_str(), link->srcEntity, link->srcPad, link->sinkEntityName.c_str(), link->sinkEntity, link->sinkPad, link->enable);
}
for (unsigned k = 0; k < mc->ctls.size(); k++) {
const McCtl* ctl = &mc->ctls[k];
LOGXML(" Ctl %s [%d] cmd %s [0x%08x] value %d", ctl->entityName.c_str(), ctl->entity, ctl->ctlName.c_str(), ctl->ctlCmd, ctl->ctlValue);
}
for (unsigned k = 0; k < mc->formats.size(); k++) {
const McFormat* format = &mc->formats[k];
if (format->formatType == FC_FORMAT)
LOGXML(" format %s [%d:%d] [%dx%d] %s", format->entityName.c_str(), format->entity, format->pad, format->width, format->height, CameraUtils::pixelCode2String(format->pixelCode));
else if (format->formatType == FC_SELECTION)
LOGXML(" select %s [%d:%d] selCmd: %d [%d, %d] [%dx%d]", format->entityName.c_str(), format->entity, format->pad, format->selCmd, format->top, format->left, format->width, format->height);
}
}
LOGXML("============End of Format Configuration===========");
}
LOGXML("@%s, line%d, for common settings==================", __func__, __LINE__);
}
} //namespace icamera