最近需要为定制的Camera添加一种特殊的数据格式,原本camera3_profiles_rkxxxx.xml有三种BLOB,YCbCr_420_888,IMPLEMENTATION_DEFINED,这三种分别对应JPEG,YUV_420_888, PRIVATE。我新增的格式无论是替代已有的三种,还是添加一种,都会导致xml无法正常解析,找了一段时间资料,发现这部分内容很少有人提及,大部分摄像头都用YCbCr_420_888这种格式搞定了,所以只能自己从头分析研究这个xml文件的解析流程,希望能找到出路。
camera3_profiles_rkxxxx.xml的读取是在hardware/rockchip/camera/common/platformdata/ChromeCameraProfiles.cpp中。
status_t ChromeCameraProfiles::init()
{
status_t status = OK;
LOGI("@%s", __FUNCTION__);
// determine the xml file name
getXmlConfigName();
status = CameraProfiles::init();
if (status) {
LOGE("CameraProfiles base init error:%d", status);
return status;
}
// Parse common sections
getDataFromXmlFile();
createConfParser();
LOGI("@%s exit!", __FUNCTION__);
return OK;
}
在hardware/rockchip/camera/common/platformdata/CameraProfiles.cpp中读取xml中的内容getDataFromXmlFile,createConfParser。
具体的细节数据操作在hardware/rockchip/camera/common/platformdata/CameraMetadataHelper.cpp中,其中使用的相关section和tag的函数如get_camera_metadata_section_name和get_camera_metadata_tag_name,实现代码在system/media/camera/src/Camera_metadata.c中。
在回到我们的目标,是为了实现添加Camera支持的数据格式。camera3_profiles_rkxxxx.xml中关于数据格式的解析是使用下面这个函数:
/**
* This function will handle all the android static metadata related elements of sensor.
*
* It will be called in the function startElement
* This method parses the input from the XML file, that can be manipulated.
* So extra care is applied in the validation of strings
*
* \param name: the element's name.
* \param atts: the element's attribute.
*/
void ChromeCameraProfiles::handleAndroidStaticMetadata(const char *name, const char **atts)
{
if (!validateStaticMetadata(name, atts))
return;
// Find tag
const metadata_tag_t *tagInfo = findTagInfo(name, android_static_tags_table, STATIC_TAGS_TABLE_SIZE);
if (tagInfo == nullptr)
return;
int count = 0;
camera_metadata_t * currentMeta = nullptr;
MetaValueRefTable mvrt;
std::vector<MetaValueRefTable> refTables;
LOGI("@%s: Parsing static tag %s: value %s", __FUNCTION__, tagInfo->name, atts[1]);
/**
* Complex parsing types done manually (exceptions)
* scene overrides uses different tables for each entry one from ae/awb/af
* mode
*/
if (tagInfo->value == ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP) {
mvrt.table = android_scaler_availableFormats_values;
mvrt.tableSize = ELEMENT(android_scaler_availableFormats_values);
refTables.push_back(mvrt);
count = parseAvailableInputOutputFormatsMap(atts[1], tagInfo, refTables,
METADATASIZE, mMetadataCache);
} else if ((tagInfo->value == ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS) ||
(tagInfo->value == ANDROID_REQUEST_AVAILABLE_RESULT_KEYS)) {
count = parseAvailableKeys(atts[1], tagInfo, METADATASIZE, mMetadataCache);
} else if (tagInfo->value == ANDROID_SYNC_MAX_LATENCY) {
count = parseEnumAndNumbers(atts[1], tagInfo, METADATASIZE, mMetadataCache);
} else { /* Parsing of generic types */
if (tagInfo->arrayTypedef == STREAM_CONFIGURATION) {
mvrt.table = android_scaler_availableFormats_values;
mvrt.tableSize = ELEMENT(android_scaler_availableFormats_values);
refTables.push_back(mvrt);
mvrt.table = android_scaler_availableStreamConfigurations_values;
mvrt.tableSize = ELEMENT(android_scaler_availableStreamConfigurations_values);
refTables.push_back(mvrt);
count = parseStreamConfig(atts[1], tagInfo, refTables, METADATASIZE, mMetadataCache);
} else if (tagInfo->arrayTypedef == STREAM_CONFIGURATION_DURATION) {
mvrt.table = android_scaler_availableFormats_values;
mvrt.tableSize = ELEMENT(android_scaler_availableFormats_values);
refTables.push_back(mvrt);
count = parseStreamConfigDuration(atts[1], tagInfo, refTables, METADATASIZE,
mMetadataCache);
} else {
count = parseGenericTypes(atts[1], tagInfo, METADATASIZE, mMetadataCache);
}
}
if (count == 0) {
LOGW("Error parsing static tag %s. ignoring", tagInfo->name);
return;
}
LOGI("@%s: writing static tag %s: count %d", __FUNCTION__,
tagInfo->name,
count);
if (mStaticMeta.size() > 0) {
currentMeta = mStaticMeta.at(mSensorIndex);
} else {
LOGE("Camera isn't added, unable to get the static metadata");
return;
}
if (add_camera_metadata_entry(currentMeta, tagInfo->value, mMetadataCache, count)) {
LOGE("call add_camera_metadata_entry fail for tag:%s", get_camera_metadata_tag_name(tagInfo->value));
}
else
// save the key to mCharacteristicsKeys used to update the
// REQUEST_AVAILABLE_CHARACTERISTICS_KEYS
mCharacteristicsKeys[mSensorIndex].push_back(tagInfo->value);
}
从其中的log看,我添加的新的数据格式可以读出。问题是出在了下面关于详细内容的解析部分:
mvrt.table = android_scaler_availableFormats_values;
mvrt.tableSize = ELEMENT(android_scaler_availableFormats_values);
refTables.push_back(mvrt);
count = parseStreamConfigDuration(atts[1], tagInfo, refTables, METADATASIZE,
mMetadataCache);
这里是把读取出来的字符和一张已知字符的表格进行了对应:
const metadata_value_t android_scaler_availableFormats_values[] = {
{"RAW16", ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 },
{"RAW_OPAQUE", ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE },
{"YV12", ANDROID_SCALER_AVAILABLE_FORMATS_YV12 },
{"YCrCb_420_SP", ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP },
{"IMPLEMENTATION_DEFINED", ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED },
{"YCbCr_420_888", ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 },
{"BLOB", ANDROID_SCALER_AVAILABLE_FORMATS_BLOB },
};
我们新增的类型,不存在与这张表格中,所以最后会出现解析异常的问题。根据已有的几种类型,添加自定义类型,就可以通过xml的解析部分了。
const metadata_value_t android_scaler_availableFormats_values[] = {
{"RAW16", ANDROID_SCALER_AVAILABLE_FORMATS_RAW16 },
{"RAW_OPAQUE", ANDROID_SCALER_AVAILABLE_FORMATS_RAW_OPAQUE },
{"YV12", ANDROID_SCALER_AVAILABLE_FORMATS_YV12 },
{"YCrCb_420_SP", ANDROID_SCALER_AVAILABLE_FORMATS_YCrCb_420_SP },
{"IMPLEMENTATION_DEFINED", ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED },
{"YCbCr_420_888", ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888 },
{"BLOB", ANDROID_SCALER_AVAILABLE_FORMATS_BLOB },
{"Y8", ANDROID_SCALER_AVAILABLE_FORMATS_Y8 },
};
不过关于添加新的数据格式还有其他内容需要更改,本文只涉及camera3_profiles_rkxxxx.xml的相关解析流程分析。