研究加载流程之前学习两个知识点
一、hash map
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
以上是百度的定义,简而言之,散列表是一种数据结构,但是其查找效率比较高,高通的chromatix name就是存放在哈希表中的。
/*创建一个哈希表*/
boolean hash_create(hash_type* obj, uint32_t hashSize)
{
hash_node_type* table;
uint32_t allocSize;
RETURN_ON_NULL(obj);
if (hashSize < DEFAULT_HASH_SIZE)
hashSize = DEFAULT_HASH_SIZE;
allocSize = hashSize * sizeof(hash_node_type); //创建一个hashsize大小的哈希表
table = (hash_node_type*) malloc(allocSize);
if (table == NULL) {
SERR("failed : memory allocation");
return FALSE;
}
memset(table, 0, allocSize );
obj->count = 0;
obj->table = table;
obj->table_size = hashSize;
return TRUE;
}
//往哈希表添加数据
boolean hash_add(hash_type* obj, const char *key,
void *data_hdl, void *data_sym, uint32_t cIndex)
{
uint32_t hash_key, index;
HASH_NODE node;
RETURN_ON_NULL(obj);
RETURN_ON_NULL(key);
RETURN_ON_NULL(data_hdl);
RETURN_ON_NULL(data_sym);
/* create hash key from a given actual key (string) */
hash_key = hash_makeHashKey(key); //可以看出哈希函数为hash_makeHashKey
index = hash_key % obj->table_size;
/* check if (key:data) is already in hash */
node = (obj->table + index)->next;
while (node) {
if (hash_key == node->hash_key) { //哈希键值存在,则返回错误
SLOW("%s is ALREADY in hash (%s:%u)", key, node->key, node->hash_key);
return FALSE;
}
node = node->next;
}
node = (hash_node_type *)malloc(sizeof(hash_node_type)); //新建一个节点
if (node == NULL) {
SERR("failed to allocate a node");
return FALSE;
}
snprintf(node->key, 256, "%s", key); //赋值给节点
node->hash_key = hash_key; //存储生成的哈希键值
node->data_hdl = data_hdl; //赋值给节点
node->data_sym = data_sym; //赋值给节点
node->cIndex = cIndex; //节点在哈希表中的第一层索引
SLOW("%s : hash_key %u : hash table index %d",
key, hash_key, index);
node->prev = obj->table + index; //以头插法将节点插入
node->next = (obj->table + index)->next;
if (node->next != NULL)
node->next->prev = node;
(obj->table + index)->next = node;
++obj->count;
return TRUE;
}
//通过键值查找数据
boolean hash_find(hash_type* obj, const char *key,
void **data_sym, uint32_t *cIndex)
{
uint32_t hash_key, index;
HASH_NODE node;
RETURN_ON_NULL(obj);
RETURN_ON_NULL(key);
RETURN_ON_NULL(data_sym);
RETURN_ON_NULL(cIndex);
if (obj->count == 0) {
SLOW("empty hash!");
return FALSE;
}
/* create hash key from a given actual key (string) */
hash_key = hash_makeHashKey(key); //通过键值生成哈希键值
index = hash_key % obj->table_size; //得到表索引
node = (obj->table + index)->next; //遍历链表
while (node) {
if (hash_key == node->hash_key) { //哈希键值相同,则查找结束,可以看书actual key通过哈希函数映射得到的哈希键值是唯一的
SLOW("%s FOUND %s:key%u:data%p",
key, node->key, node->hash_key, node->data_sym);
*data_sym = node->data_sym;
*cIndex = node->cIndex;
return TRUE;
}
node = node->next;
}
*data_sym = NULL;
SLOW("%s NOT in HASH", key);
return FALSE;
}
//哈希函数,实际调用crc32
static uint32_t hash_makeHashKey(const char *key)
{
return crc32(0, key, strlen(key));
}
二、LRU map
LRU(Least Recently Used)表也是一种数据结构,利用LRU算法可以比较方便的找到最新最少使用的节点。
这里根据算法画了几个图,第一张是初始化部分,创建一个长度为30的LRU表,可以先看看结构体定义
typedef struct {
LIST_NODE *list_node; //LRU表头,是个二级指针,也可看作数组的首地址
uint32_t node_count; /* 最大节点数,创建表时赋值*/
list_type list; //存储当前list的头尾数据以及list大小
} chromatix_lru_type; //LRU表结构体
typedef struct {
uint32_t count; /* number of nodes */
LIST_NODE front; /* the first item in list */
LIST_NODE back; /* the last item in list */
} list_type;
typedef struct list_node_tag {
struct list_node_tag *prev;
struct list_node_tag *next;
uint32_t cIndex;
char key[256];
} list_node_type, *LIST_NODE;
boolean lru_create(chromatix_lru_type *obj, uint32_t node_count) //创建函数
{
RETURN_ON_NULL(obj);
if (node_count == 0) {
SERR("wrong node count");
return FALSE;
}
obj->list_node = (LIST_NODE *)malloc(sizeof(LIST_NODE) * node_count); //直接开辟了所有节点内存
if (obj->list_node == NULL) {
SERR("failed : memory allocation");
return FALSE;
}
/* create list structure */
list_create(&obj->list);
obj->node_count = node_count;
return TRUE;
}
上图是表添加节点流程,创建LRU表后所有节点处于未使用状态,当需要添加节点元素时有两种情况,第一种是当前开辟的所有节点还没有利用完,我们创建表时开辟了30个元素,所以前面三十个元素添加都是通过这种方式,第二种情况是所有节点已全部利用完,这时需要替换掉其中一个节点的方式插入,替换方式有两种,一种是替换掉最旧节点,一种是替换最新节点。上图表示以push_back的方式将节点插入表中
boolean lru_add(chromatix_lru_type *obj, const char *key, uint32_t *cIndex)
{
LIST_NODE node;
uint32_t count;
RETURN_ON_NULL(obj);
RETURN_ON_NULL(cIndex);
count = list_count(&obj->list);
/* If cache has space, then use an empty slot.
Otherwise, remove the least recent slot and return the slot */
if (count < obj->node_count) {
*cIndex = count;
obj->list_node[*cIndex] = list_pushBack(&obj->list, *cIndex, key);
} else {
node = list_back(&obj->list);
if (NULL == node)
{
return FALSE;
}
*cIndex = node->cIndex;
list_popBack(&obj->list);
obj->list_node[*cIndex] = list_pushFront(&obj->list, *cIndex, key);
}
return TRUE;
}
LIST_NODE list_pushBack(list_type *list, uint32_t cIndex, const char *key)
{
LIST_NODE node = NULL;
if (!list || !key) {
SERR("failed NULL pointer detected");
return NULL;
}
node = createNode(cIndex, key);
if (!node) {
SERR("failed: createNode");
return NULL;
}
node->next = NULL;
node->prev = list->back;
if (list->back)
list->back->next = node;
list->back = node;
if (!list->front)
list->front = node;
++list->count;
return node;
}
上图是更新一个cIndex=2的节点的场景,假如该键值的数据有变化,我们将其置为列表的最前端,首先将更新节点从list列表中删除,再创建一个新的节点,占用原来LRU表的坑位,将该节点置为list列表表头位置。list的back不变,front指针指向新更新的节点。下面是代码部分:
boolean lru_update(chromatix_lru_type *obj, uint32_t cIndex)
{
LIST_NODE data;
char key[256];
RETURN_ON_NULL(obj);
data = obj->list_node[cIndex];
RETURN_ON_NULL(data);
snprintf(key, 256, "%s", data->key);
SLOW("%s updated", data->key);
list_erase(&obj->list, obj->list_node[cIndex]);
obj->list_node[cIndex] = list_pushFront(&obj->list, cIndex, key);
return TRUE;
}
LIST_NODE list_pushFront(list_type *list, uint32_t cIndex, const char *key)
{
LIST_NODE node = NULL;
if (!list || !key) {
SERR("failed NULL pointer detected");
return NULL;
}
node = createNode(cIndex, key);
if (!node) {
SERR("failed: createNode");
return NULL;
}
node->prev = NULL;
node->next = list->front;
if (list->front)
list->front->prev = node;
list->front = node;
if (!list->back)
list->back = node;
++list->count;
return node;
}
三、chromatix加载
熟悉了这两种数据结构之后,接下来分析高通chromatix文件的加载流程,相信你也像我一样想知道,选用不用的分辨率是怎么加载对应的效果参数文件的,以及预览拍照录像模式下走的是哪一组参数。
初始化部分:
高通的效果参数文件是通过XML文件配置的,系统去解析XML文件,存储对应的key值,即各个模式下调用的参数文件名称,然后加载对应的库文件,用一个hash表来维护这些数据。
<ChromatixConfigurationRoot>
<CommonChromatixInfo>
<ChromatixName special_mode_mask="0">
<ISPCommon>ov5675_common</ISPCommon>
<PostProc>ov5675_postproc</PostProc>
</ChromatixName>
</CommonChromatixInfo>
<ResolutionChromatixInfo>
<ChromatixName sensor_resolution_index="0" special_mode_mask="0">
<ISPPreview>ov5675_snapshot</ISPPreview>
<ISPSnapshot>ov5675_snapshot</ISPSnapshot>
<ISPVideo>ov5675_default_video</ISPVideo>
<CPPPreview>ov5675_cpp_preview</CPPPreview>
<CPPSnapshot>ov5675_cpp_snapshot</CPPSnapshot>
<CPPVideo>ov5675_cpp_video</CPPVideo>
<CPPLiveshot>ov5675_cpp_liveshot</CPPLiveshot>
<A3Preview>ov5675_default_preview_3a</A3Preview>
<A3Video>ov5675_zsl_video_3a</A3Video>
</ChromatixName>
<ChromatixName sensor_resolution_index="1" special_mode_mask="0">
<ISPPreview>ov5675_snapshot</ISPPreview>
<ISPSnapshot>ov5675_snapshot</ISPSnapshot>
<ISPVideo>ov5675_default_video</ISPVideo>
<CPPPreview>ov5675_cpp_preview</CPPPreview>
<CPPSnapshot>ov5675_cpp_snapshot</CPPSnapshot>
<CPPVideo>ov5675_cpp_video</CPPVideo>
<CPPLiveshot>ov5675_cpp_liveshot</CPPLiveshot>
<A3Preview>ov5675_default_preview_3a</A3Preview>
<A3Video>ov5675_zsl_video_3a</A3Video>
</ChromatixName>
<ChromatixName sensor_resolution_index="2" special_mode_mask="0">
<ISPPreview>ov5675_snapshot</ISPPreview>
<ISPSnapshot>ov5675_snapshot</ISPSnapshot>
<ISPVideo>ov5675_default_video</ISPVideo>
<CPPPreview>ov5675_cpp_preview</CPPPreview>
<CPPSnapshot>ov5675_cpp_snapshot</CPPSnapshot>
<CPPVideo>ov5675_cpp_video</CPPVideo>
<CPPLiveshot>ov5675_cpp_liveshot</CPPLiveshot>
<A3Preview>ov5675_default_preview_3a</A3Preview>
<A3Video>ov5675_zsl_video_3a</A3Video>
</ChromatixName>
<ChromatixName sensor_resolution_index="3" special_mode_mask="0">
<ISPPreview>ov5675_snapshot</ISPPreview>
<ISPSnapshot>ov5675_snapshot</ISPSnapshot>
<ISPVideo>ov5675_default_video</ISPVideo>
<CPPPreview>ov5675_cpp_preview</CPPPreview>
<CPPSnapshot>ov5675_cpp_snapshot</CPPSnapshot>
<CPPVideo>ov5675_cpp_video</CPPVideo>
<CPPLiveshot>ov5675_cpp_liveshot</CPPLiveshot>
<A3Preview>ov5675_default_preview_3a</A3Preview>
<A3Video>ov5675_zsl_video_3a</A3Video>
</ChromatixName>
</ResolutionChromatixInfo>
</ChromatixConfigurationRoot>
需要对比设置chromatix的xml文件来看
static boolean sensor_xml_util_parse_chromatix_config(
camera_module_config_t *configPtr)
{
boolean ret = FALSE;
xmlNodePtr nodePtr = NULL;
xmlDocPtr chromatixDocPtr = NULL;
xmlNodePtr chromatixRootPtr = NULL;
char chromatix_xml_name[NAME_SIZE_MAX];
/* Create the xml path */
snprintf(chromatix_xml_name, NAME_SIZE_MAX, "%s%s.xml",
CONFIG_XML_PATH, configPtr->chromatix_name); //取得xml路径 /data/vendor/camera/ov5675_chromatix.xml
if (access(chromatix_xml_name, R_OK)) {
SHIGH("cannot read file %s. Trying from system partition",
chromatix_xml_name);
/* Create the xml path from system partition */
snprintf(chromatix_xml_name, NAME_SIZE_MAX, "%s%s.xml",
CONFIG_XML_SYSTEM_PATH, configPtr->chromatix_name);
if (access(chromatix_xml_name, R_OK)) {
SERR("Cannot read file from %s. read failed",
chromatix_xml_name);
return FALSE;
}
}
SLOW("reading from file %s", chromatix_xml_name);
/* Get the Root pointer and Document pointer of XMl file */
RETURN_ON_FALSE(sensor_xml_util_load_file(chromatix_xml_name,
&chromatixDocPtr, &chromatixRootPtr, "ChromatixConfigurationRoot")); //得到root节点
configPtr->chromatix_info.size = 0;
nodePtr = sensor_xml_util_get_node(chromatixRootPtr,
"ResolutionChromatixInfo", 0); //先解析ResolutionChromatixInfo节点
if (nodePtr == NULL) {
ret = FALSE;
SERR("Could not get nodePtr for ResolutionChromatixInfo");
goto CHROMATIX_CONFIG_EXIT;
}
ret = sensor_xml_util_parse_chromatix_name(
configPtr, nodePtr, chromatixDocPtr, FALSE);
if (ret == FALSE) {
SERR("sensor_xml_util_parse_chromatix_name failed");
goto CHROMATIX_CONFIG_EXIT;
}
nodePtr = sensor_xml_util_get_node(chromatixRootPtr,
"CommonChromatixInfo", 0); ////先解析CommonChromatixInfo节点
if (nodePtr == NULL) {
ret = FALSE;
SERR("Could not get nodePtr for CommonChromatixInfo");
goto CHROMATIX_CONFIG_EXIT;
}
ret = sensor_xml_util_parse_chromatix_name(
configPtr, nodePtr, chromatixDocPtr, TRUE);
if (ret == FALSE) {
SERR("sensor_xml_util_parse_chromatix_name failed");
goto CHROMATIX_CONFIG_EXIT;
}
CHROMATIX_CONFIG_EXIT:
sensor_xml_util_unload_file(chromatixDocPtr);
return ret;
}
然后跟进sensor_xml_util_parse_chromatix_name函数:
static boolean sensor_xml_util_parse_chromatix_name(
camera_module_config_t *configPtr, xmlNodePtr nodePtr,
xmlDocPtr chromatixDocPtr, uint8_t is_common_chroamtix)
{
......
chroamtix_arr_size = sensor_xml_util_get_num_nodes(nodePtr, "ChromatixName"); //chroamtix_arr_size=4
if (chroamtix_arr_size == 0) {
SERR("No nodes in ChromatixName");
return FALSE;
}
SLOW("num_modes = %d", chroamtix_arr_size);
for (count = 0; count < chroamtix_arr_size; count++, i++) {
num_pairs = 0;
if (is_common_chroamtix) {
configPtr->chromatix_info.chromatix_name[i].sensor_resolution_index =
0xFF;
} else {
strlcpy(key_value_pair[num_pairs].key, "sensor_resolution_index",
MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
&(configPtr->chromatix_info.chromatix_name[i].sensor_resolution_index);
key_value_pair[num_pairs].value_type = XML_VALUE_UINT8;
key_value_pair[num_pairs].nodeType = XML_ATTRIBUTE_NODE;
num_pairs++;
}
memset(special_mode_str, 0, sizeof (special_mode_str));
strlcpy(key_value_pair[num_pairs].key, "special_mode_mask", MAX_KEY_SIZE);
key_value_pair[num_pairs].value = special_mode_str;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ATTRIBUTE_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "ISPCommon", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].isp_common;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "ISPPreview", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].isp_preview;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "ISPSnapshot", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].isp_snapshot;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "ISPVideo", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].isp_video;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "CPPPreview", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].cpp_preview;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "CPPSnapshot", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].cpp_snapshot;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "CPPVideo", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].cpp_video;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "CPPLiveshot", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].cpp_liveshot;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "PostProc", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].postproc;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "A3Preview", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].a3_preview;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "A3Video", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].a3_video;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "External", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].external;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
strlcpy(key_value_pair[num_pairs].key, "Iot", MAX_KEY_SIZE);
key_value_pair[num_pairs].value =
configPtr->chromatix_info.chromatix_name[i].iot;
key_value_pair[num_pairs].value_type = XML_VALUE_STRING;
key_value_pair[num_pairs].nodeType = XML_ELEMENT_NODE;
num_pairs++;
RETURN_ON_FALSE(sensor_xml_util_get_node_data(chromatixDocPtr, nodePtr,
"ChromatixName", key_value_pair, num_pairs, count)); //真正读取xml文件节点内容
/*key_value_pair只是一个临时局部变量,为了方便xml节点的解析,最终节点内容解析到configPtr-
>chromatix_info.chromatix_name中*/
RETURN_ON_FALSE(sensor_xml_util_parse_special_mode(special_mode_str,
&(configPtr->chromatix_info.chromatix_name[i])));
}
configPtr->chromatix_info.size+= chroamtix_arr_size;
return TRUE;
}
最终节点内容存储在chromatix_info中,共有5组输入,res 4组,common一组,结构体定义如下:
typedef struct {
unsigned char special_mode_type;
unsigned long long int special_mode_mask;
unsigned char sensor_resolution_index;
char isp_common[NAME_SIZE_MAX];
char isp_preview[NAME_SIZE_MAX];
char isp_snapshot[NAME_SIZE_MAX];
char isp_video[NAME_SIZE_MAX];
char cpp_preview[NAME_SIZE_MAX];
char cpp_snapshot[NAME_SIZE_MAX];
char cpp_video[NAME_SIZE_MAX];
char cpp_liveshot[NAME_SIZE_MAX];
char postproc[NAME_SIZE_MAX];
char a3_preview[NAME_SIZE_MAX];
char a3_video[NAME_SIZE_MAX];
char external[NAME_SIZE_MAX];
char iot[NAME_SIZE_MAX];
} module_chromatix_name_t;
typedef struct {
module_chromatix_name_t chromatix_name[MAX_CHROMATIX_ARRAY];
uint16_t size;
} module_chromatix_info_t;
chromatix_info存储的只是键值信息,那实际上我们还需要加载相应的效果参数库文件才行,毕竟我们需要的不是一个名字,而是实际的参数值,参数是通过一个chromatix manager来管理的,库文件加载流程在module_sensor_init_chromatix中:
static boolean module_sensor_init_chromatix(void *data, void *eebin_hdl)
{
module_sensor_bundle_info_t *s_bundle;
sensor_lib_t *sensor_lib_ptr;
sensor_func_tbl_t func_tbl;
boolean rc = TRUE;
SLOW("Enter");
RETURN_ON_NULL(data);
s_bundle = (module_sensor_bundle_info_t *)data;
sensor_lib_ptr = s_bundle->sensor_lib_params->sensor_lib_ptr;
/* No EEPROM */
if (s_bundle->sensor_info->subdev_id[SUB_MODULE_EEPROM] == -1) {
rc = cm_create(&s_bundle->chromatix_manager,
s_bundle->sensor_info->sensor_name,
&s_bundle->sensor_common_info.camera_config.chromatix_info,
NULL, eebin_hdl);
if (rc == FALSE) {
SERR("failed: create cm");
return FALSE;
}
/* EEPROM : pass the eeprom handle for calibration */
} else {
eeprom_sub_module_init(&func_tbl);
if (func_tbl.open((void **)&s_bundle->eeprom_data,
&s_bundle->subdev_info[SUB_MODULE_EEPROM]) < 0) {
SERR("Failed EEPROM_OPEN");
return FALSE;
}
rc = cm_create(&s_bundle->chromatix_manager,
s_bundle->sensor_info->sensor_name,
&s_bundle->sensor_common_info.camera_config.chromatix_info,
s_bundle->eeprom_data, eebin_hdl);
if (rc == FALSE) {
SERR("failed: create cm");
if (func_tbl.close(s_bundle->eeprom_data) < 0)
SERR("Failed EEPROM_CLOSE");
return FALSE;
}
if (func_tbl.close(s_bundle->eeprom_data) < 0) {
cm_destroy(&s_bundle->chromatix_manager);
SERR("Failed EEPROM_CLOSE");
return FALSE;
}
}
SLOW("Exit");
return TRUE;
}
我们只需要关注cm_create:
boolean cm_create(chromatix_manager_type* cm,
const char *sensor_name,
module_chromatix_info_t *chromatix_array,
sensor_eeprom_data_t *eeprom_ctrl, void *eebin_hdl)
{
module_chromatix_name_t *chromatix_name;
uint32_t i;
boolean rc;
RETURN_ON_NULL(cm);
RETURN_ON_NULL(sensor_name);
/* chromatix_array can be NULL */
/* eeprom_ctrl can be NULL */
/* eebin_hdl can be NULL */
SLOW("Enter for %s", sensor_name);
if (chromatix_array->size == 0) {
SERR("YUV sensor : no chromatix loading");
return TRUE;
}
if (hash_create(&cm->hash, 0) == FALSE) { //创建一个hash表
SERR("failed to create hash");
return FALSE;
}
if (lru_create(&cm->lru, MAX_CHROMATIX_COUNT) == FALSE) { //创建一个LRU表
SERR("failed to create LRU");
return FALSE;
}
pthread_mutex_init(&cm->mutex, NULL);
cm->mutex_created = TRUE;
cm->eeprom_ctrl = eeprom_ctrl;
if (eeprom_ctrl) {
cm->eeprom_func = (sensor_func_tbl_t *)malloc(sizeof(sensor_func_tbl_t));
RETURN_ON_NULL(cm->eeprom_func);
eeprom_sub_module_init(cm->eeprom_func);
} else
cm->eeprom_func = NULL;
cm->eebin_hdl = eebin_hdl;
bin_ctl.cmd = EEPROM_BIN_GET_LIB_NAME_DATA;
bin_ctl.ctl.q_num.type = EEPROM_BIN_LIB_CHROMATIX;
/* add all chromatix libraries */
for (i = 0; i < chromatix_array->size; i++) {
chromatix_name = &chromatix_array->chromatix_name[i];
rc = addLib(cm, chromatix_name->isp_common, EEPROM_CALIBRATE_LSC);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->isp_preview, EEPROM_CALIBRATE_WB_GREEN);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->isp_snapshot, EEPROM_CALIBRATE_WB_GREEN);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->isp_video, EEPROM_CALIBRATE_WB_GREEN);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->cpp_preview, 0);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->cpp_snapshot, 0);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->cpp_video, 0);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->cpp_liveshot, 0);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->postproc, 0);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->a3_video, EEPROM_CALIBRATE_WB);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->a3_preview, EEPROM_CALIBRATE_WB);
CHECK_RETURN(rc);
rc = addLib(cm, chromatix_name->iot, 0);
CHECK_RETURN(rc);
if (lru_count(&cm->lru) == MAX_CHROMATIX_COUNT) {
SERR("HASH cache is full");
break;
}
}
lru_traverse(&cm->lru);
SLOW("Exit");
return TRUE;
ERROR:
if (cm->mutex_created) {
pthread_mutex_destroy(&cm->mutex);
cm->mutex_created = FALSE;
}
SERR("failed");
return FALSE;
}
==》
static boolean addLib(chromatix_manager_type* cm, const char *key,
int32_t cal_type)
{
void *data_hdl = NULL;
void *data_sym = NULL;
uint32_t cIndex;
int32_t rc;
if (strlen(key) == 0) return TRUE;
SLOW("chromatix: %s", key);
if (lru_count(&cm->lru) == MAX_CHROMATIX_COUNT) {
SERR("HASH cache is full");
return TRUE;
}
/* check if chromatix library is already in hash */
if (hash_find(&cm->hash, key, &data_sym, &cIndex) == TRUE)
return TRUE;
if (addLib_getSymbol(cm, key, cal_type) == NULL) {
SERR("failed to add chromatix to hash");
return FALSE;
}
return TRUE;
}
==》
static void* addLib_getSymbol(chromatix_manager_type* cm, const char *key,
int32_t cal_type)
{
void *data_hdl = NULL;
void *data_sym = NULL;
uint32_t cIndex;
int32_t rc;
if (key == NULL) return NULL;
SLOW("chromatix: %s", key);
/* open library */
bin_ctl.ctl.name_data.lib_name = (char *)key;
bin_ctl.ctl.name_data.path = NULL;
if (cm->eebin_hdl)
if (eebin_interface_control(cm->eebin_hdl, &bin_ctl) < 0)
SERR("No Camera Multimodule data.");
rc = load_chromatix(key, bin_ctl.ctl.name_data.path,
&data_hdl, &data_sym);
//这里就是加载效果参数库文件的地方了,key表示文件名称,比如ov5675_cpp_preview,data_hdl表示打开库文件操作句柄,data_sym表示参数数据指针。
if (rc != SENSOR_SUCCESS) {
SERR("fail : load_chromatix %s", key);
return NULL;
}
/* calibration */
if (cm->eeprom_ctrl && cm->eeprom_func && cal_type > 0)
((sensor_func_tbl_t*)(cm->eeprom_func))->process(
cm->eeprom_ctrl, cal_type, data_sym);
if (lru_add(&cm->lru, key, &cIndex) == FALSE)
goto ERROR;
if (hash_add(&cm->hash, key, data_hdl, data_sym, cIndex)
== FALSE)
goto ERROR;
return data_sym;
ERROR:
unload_chromatix(data_hdl, data_sym);
return NULL;
}
==》
cal_type参数表示的是加载库的时候做一次校准操作,如果有otp的话,会跑一回eeprom_func->process函数。
可以看出chromatix manager在初始化的时候,根据开机时候解析XML文件得到的chromatix_array加载所有的效果参数库文件,这里并没有做其他的分类处理,数据与数据之间是没有任何逻辑的,就是单纯将所有数据加载进hash表,LRU表存储键值,hash表存储键值和参数,两个表是通过cIndex建立关联的,cIndex由LRU表添加节点时生成,hash表节点中存储一份拷贝。
参数文件加载了以后,那应该如何加载对应的参数文件呢?首先通过module_chromatix_name_t的定义可以看出,isp,cpp,3a模块都支持preview,snapshot,video三种模式的参数,另外还有common模式,postproc模式,所以,只要保证我们能够确定好一组key值的配置,那系统就可以在pipeline的对应模块正确的加载对应的参数。当前调用哪组key值设置在sensor_get_cur_chromatix_name中:
static int32_t sensor_get_cur_chromatix_name(void *sctrl, void *data)
{
sensor_ctrl_t *ctrl;
sensor_chromatix_params_t *param;
char **name;
module_chromatix_name_t *chromatix_name = NULL;
sensor_submod_common_info_t *sensor_common_info = NULL;
int16_t cur_res, i;
RETURN_ERROR_ON_NULL(sctrl);
RETURN_ERROR_ON_NULL(data);
ctrl = (sensor_ctrl_t *)sctrl;
param = (sensor_chromatix_params_t *)data;
name = param->chromatix_lib_name;
cur_res = (ctrl->s_data->cur_res <= SENSOR_INVALID_RESOLUTION) ?
0 : ctrl->s_data->cur_res;
if (cur_res >
ctrl->s_data->sensor_common_info->camera_config.chromatix_info.size ||
cur_res >= MAX_CHROMATIX_ARRAY) {
SERR("failed cur res %d max size %d", cur_res,
ctrl->s_data->sensor_common_info->camera_config.chromatix_info.size);
return SENSOR_ERROR_INVAL;
}
sensor_common_info = ctrl->s_data->sensor_common_info;
chromatix_name =
&(sensor_common_info->camera_config.chromatix_info.chromatix_name[cur_res]);
SLOW("special_mode_mask = %lld", sensor_common_info->special_mode_mask);
for (i = 0; i < SENSOR_CHROMATIX_MAX; i++)
name[i] = NULL;
name[SENSOR_CHROMATIX_ISP_COMMON] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_ISP,
SENSOR_CHROMATIX_TYPE_COMMON);
name[SENSOR_CHROMATIX_ISP] = name[SENSOR_CHROMATIX_ISP_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_ISP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
name[SENSOR_CHROMATIX_CPP_PREVIEW] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_PREVIEW);
name[SENSOR_CHROMATIX_CPP_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_FLASH, TRUE);
name[SENSOR_CHROMATIX_CPP_FLASH_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_FLASH, FALSE);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_OIS_CAPTURE, TRUE);
name[SENSOR_CHROMATIX_CPP_OIS_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_OIS_CAPTURE, FALSE);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_DOWNSCALE, TRUE);
name[SENSOR_CHROMATIX_CPP_OIS_DS_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_DOWNSCALE, FALSE);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_UPSCALE, TRUE);
name[SENSOR_CHROMATIX_CPP_OIS_US_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_UPSCALE, FALSE);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_DOWNSCALE, TRUE);
name[SENSOR_CHROMATIX_CPP_DS] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_DOWNSCALE, FALSE);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_UPSCALE, TRUE);
name[SENSOR_CHROMATIX_CPP_US] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_SNAPSHOT);
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_ZOOM_UPSCALE, FALSE);
if (sensor_common_info->ir_mode)
sensor_util_set_special_mode(ctrl->s_data->sensor_common_info,
SENSOR_SPECIAL_MODE_IR, TRUE);
name[SENSOR_CHROMATIX_CPP_VIDEO] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_VIDEO);
name[SENSOR_CHROMATIX_SW_PPROC] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_SW_PPROC,
SENSOR_CHROMATIX_TYPE_COMMON);
name[SENSOR_CHROMATIX_3A] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_3A,
SENSOR_CHROMATIX_TYPE_PREVIEW);
name[SENSOR_CHROMATIX_EXTERNAL] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_EXTERNAL,
SENSOR_CHROMATIX_TYPE_COMMON);
name[SENSOR_CHROMATIX_IOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_IOT,
SENSOR_CHROMATIX_TYPE_COMMON);
if (ctrl->s_data->sensor_common_info->sensor_mode == SENSOR_MODE_VIDEO) {
name[SENSOR_CHROMATIX_ISP] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_ISP,
SENSOR_CHROMATIX_TYPE_VIDEO);
name[SENSOR_CHROMATIX_CPP_SNAPSHOT] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_CPP,
SENSOR_CHROMATIX_TYPE_LIVESHOT);
name[SENSOR_CHROMATIX_3A] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_3A,
SENSOR_CHROMATIX_TYPE_VIDEO);
} else if(ctrl->s_data->sensor_common_info->sensor_mode ==
SENSOR_MODE_PREVIEW || ctrl->s_data->sensor_common_info->sensor_mode == SENSOR_MODE_ZSL) {
name[SENSOR_CHROMATIX_ISP] =
sensor_get_cur_chromatix_name_for_type(ctrl->s_data, CAMERA_MODULE_ISP,
SENSOR_CHROMATIX_TYPE_PREVIEW);
}
for (i = 0; i < SENSOR_CHROMATIX_MAX; i++)
if (name[i]) {
SLOW("res_idx = %d chromatix_lib_name[%d] = %s",cur_res, i, name[i]);
} else {
SLOW("res_idx = %d chromatix_lib_name[%d] = %s",cur_res, i, "NULL");
}
return SENSOR_SUCCESS;
}
==>
static char * sensor_get_cur_chromatix_name_for_type(
sensor_data_t *s_data, camera_module module,
sensor_chroamtix_type stream_type) //根据camera_module和stream_type加载当前resolution对应的key info array
{
uint32_t i = 0;
uint32_t j = 0;
char *name = NULL;
module_chromatix_name_t *chromatix_name = NULL;
module_chromatix_info_t *chromatix_info =
&s_data->sensor_common_info->camera_config.chromatix_info;
uint64_t special_mode_mask =
s_data->sensor_common_info->special_mode_mask;
uint8_t res_idx =
(s_data->cur_res == SENSOR_INVALID_RESOLUTION) ? 0 : s_data->cur_res;
uint64_t index_array[4][2] =
{
{res_idx, special_mode_mask}, {0xFF, special_mode_mask},
{res_idx, 0}, {0xFF, 0},
};
for (j = 0; j < 4; j++) {
for (i = 0; i < chromatix_info->size; i++) {
chromatix_name = &chromatix_info->chromatix_name[i];
SLOW("index_array[%d][0] = %lld sensor_resolution_index = %d", j,
index_array[j][0], chromatix_name->sensor_resolution_index);
/* Check if the res_idx matches with the the one in chromatix array */
if (index_array[j][0] != chromatix_name->sensor_resolution_index)
continue;
SLOW("index_array[%d][1] = %lld special_mode_mask = %lld", j,
index_array[j][1], chromatix_name->special_mode_mask);
/* Check if special_mode_mask matches with the one in chromatix array in xml file */
if (chromatix_name->special_mode_type) {
/* If special_mode_type is set, then the chroamtix modes have | (or) */
if ((index_array[j][1] & chromatix_name->special_mode_mask) !=
index_array[j][1])
continue;
}
else if (index_array[j][1] != chromatix_name->special_mode_mask)
continue;
switch (module) {
case CAMERA_MODULE_ISP:
switch (stream_type) {
case SENSOR_CHROMATIX_TYPE_PREVIEW:
name = chromatix_name->isp_preview;
break;
case SENSOR_CHROMATIX_TYPE_SNAPSHOT:
name = chromatix_name->isp_snapshot;
break;
case SENSOR_CHROMATIX_TYPE_VIDEO:
name = chromatix_name->isp_video;
break;
case SENSOR_CHROMATIX_TYPE_COMMON:
name = chromatix_name->isp_common;
break;
default:
SERR("Invalid stream type = %d", stream_type);
break;
}
break;
case CAMERA_MODULE_CPP:
switch (stream_type) {
case SENSOR_CHROMATIX_TYPE_PREVIEW:
name = chromatix_name->cpp_preview;
break;
case SENSOR_CHROMATIX_TYPE_SNAPSHOT:
name = chromatix_name->cpp_snapshot;
break;
case SENSOR_CHROMATIX_TYPE_VIDEO:
name = chromatix_name->cpp_video;
break;
case SENSOR_CHROMATIX_TYPE_LIVESHOT:
name = chromatix_name->cpp_liveshot;
break;
default:
SERR("Invalid stream type = %d", stream_type);
break;
}
break;
case CAMERA_MODULE_3A:
switch (stream_type) {
case SENSOR_CHROMATIX_TYPE_PREVIEW:
case SENSOR_CHROMATIX_TYPE_SNAPSHOT:
if(chromatix_name->external)
name = chromatix_name->external;
else
name = chromatix_name->a3_preview;
break;
case SENSOR_CHROMATIX_TYPE_VIDEO:
case SENSOR_CHROMATIX_TYPE_LIVESHOT:
name = chromatix_name->a3_video;
break;
default:
SERR("Invalid stream type = %d", stream_type);
break;
}
break;
case CAMERA_MODULE_SW_PPROC:
name = chromatix_name->postproc;
break;
case CAMERA_MODULE_EXTERNAL:
name = chromatix_name->external;
break;
case CAMERA_MODULE_IOT:
name = chromatix_name->iot;
break;
default:
SERR("Invalid module = %d", module);
break;
}
if ((name != NULL) && strlen(name)) {
SLOW("name = %s", name);
return name;
}
else if (special_mode_mask == 0 && j == 1)
goto CHROMATIX_NULL;
}
}
CHROMATIX_NULL:
SHIGH("chromatix for res_idx = %d special_mode_mask = %lld \
module = %d chromatix_type = %d is NULL",
res_idx, special_mode_mask, module, stream_type);
return NULL;
}
下一步是获取对应的效果参数的指针:
static int32_t chromatix_get_ptr(chromatix_data_t *ctrl, void *data)
{
int32_t i;
sensor_chromatix_params_t *params;
SLOW("Enter");
RETURN_ERROR_ON_NULL(ctrl);
RETURN_ERROR_ON_NULL(data);
params = (sensor_chromatix_params_t *)data;
for(i = 0; i < SENSOR_CHROMATIX_MAX; i++) {
SLOW("type[%d]:[%s]", i, params->chromatix_lib_name[i]);
if (params->chromatix_lib_name[i] == ctrl->chromatix_name[i])
params->chromatix_reloaded[i] = FALSE;
else
params->chromatix_reloaded[i] = TRUE;
if (i == SENSOR_CHROMATIX_EXTERNAL) continue;
if (!params->chromatix_lib_name[i]) {
params->chromatix_ptr[i] = NULL;
continue;
}
ctrl->chromatix_ptr[i] =
cm_getChromatix(ctrl->cm, params->chromatix_lib_name[i],
pick_calibration_type[i]);
if (!ctrl->chromatix_ptr[i]) {
SERR("Can't get chromatix pointer : %s", params->chromatix_lib_name[i]);
return SENSOR_FAILURE;
}
params->chromatix_ptr[i] = ctrl->chromatix_ptr[i];
SLOW("chromatix version: 0x%x",
((chromatix_parms_type*)ctrl->chromatix_ptr[i])
->chromatix_version_info.chromatix_version);
ctrl->chromatix_name[i] = params->chromatix_lib_name[i];
}
SLOW("Exit");
return SENSOR_SUCCESS;
}
==>
void *cm_getChromatix(chromatix_manager_type* cm, const char *name,
uint32_t calibration_type)
{
void *data_sym = NULL;
void *data_hdl = NULL;
char *key = NULL;
uint32_t cIndex;
if (!cm || !name) {
SERR("NULL pointer detected");
return NULL;
}
SLOW("%s", name);
PTHREAD_MUTEX_LOCK(&cm->mutex);
if (hash_find(&cm->hash, name, &data_sym, &cIndex)) {
/* Chromatix file is in the hash : update LRU */ //如果要加载的库已存在hash表,获取数据,并更新LRU表
lru_update(&cm->lru, cIndex);
} else {
SLOW("Can't find the data of key[%s]", name);
/* Chromatix file is NOT in the hash :
(1) cache memory is available, add
(2) delete least used file from cache, and add */
if (lru_count(&cm->lru) < MAX_CHROMATIX_COUNT) {
data_sym = addLib_getSymbol(cm, name, calibration_type);
} else { //当加载的库没有在hash表中,并且LRU表坑占满了,则需要先把最旧节点从hash表中删除,再unload参数,释放文件句柄和内存。如果不进行这一步操作,会造成LRU表会比hash表少一个数据,因为LRU新增数据如果cache不够了,会将新增节点替换旧节点,它最多只能存储MAX_CHROMATIX_COUNT个数据。不过现在也不知道这个LRU表是干嘛用的==
/* get the least used chromatix file info */
lru_getLeastRecent(&cm->lru, &key, &cIndex);
/* delete has node and unload the library */
hash_delete(&cm->hash, key, &data_hdl, &data_sym);
unload_chromatix(data_hdl, data_sym);
data_sym = addLib_getSymbol(cm, name, calibration_type);
if (data_sym == NULL)
SERR("failed : addLib2");
}
}
lru_traverse(&cm->lru);
PTHREAD_MUTEX_UNLOCK(&cm->mutex);
return data_sym;
}
至此,结束!