CameraApp里面用户操作的设置项分为两类:
- 一类由App自行处理,比如照片保存路径、绘制九宫格参照线、拍照声音等等
- 一类需要经由framework下发到hal,然后进一步流转到相应的算法库中去处理
本题我们以用户设置AE补偿参数为例,来跟踪第二种情况下的参数设置流程。 代码路径:vendor\sprd\modules\libcamera
hal3_2v6下:
一,hal中第一步接受参数的地方就是SprdCamera3Settings.cpp,我们在之前的文章中有介绍这个类,SprdCamera3Settings.cpp管理者android原生和平台Sprd自定义的参数。
在其updateWorkParameters函数中,会从CameraMetadata类型的frame_settings对象中读取参数值,然后设置到s_setting[mCameraId] ,即 sprd_setting_info_t 结构体中,该结构体正是我们上篇文章介绍的 保存camera所有参数的结构体
if (frame_settings.exists(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION)) {
if (s_setting[mCameraId].controlInfo.ae_exposure_compensation !=
frame_settings.find(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION)
.data.i32[0]) {
s_setting[mCameraId].controlInfo.ae_manual_trigger = 1;
s_setting[mCameraId].controlInfo.ae_comp_effect_frames_cnt =
EV_EFFECT_FRAME_NUM;
s_setting[mCameraId].controlInfo.ae_exposure_compensation =
frame_settings.find(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION)
.data.i32[0];
HAL_LOGD("cyy_ae_exposure_compensation=%d",
s_setting[mCameraId].controlInfo.ae_exposure_compensation);
pushAndroidParaTag(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION);
}
}
从frame_settings中读出 ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION 值,调用了pushAndroidParaTag,以便在以下一步中获取此参数。
二, SprdCamera3OEMIf.cpp 的 SetCameraParaTag 函数 在此函数中,读出上一步中设置的AE参数值,并且继续玩OEM层设置
case ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION:
SPRD_DEF_Tag *sprddefInfo;
struct cmr_ae_compensation_param ae_compensation_param;
sprddefInfo = mSetting->getSPRDDEFTagPTR();
if (sprddefInfo->sprd_appmode_id == CAMERA_MODE_MANUAL) {
ae_compensation_param.ae_compensation_range[0] =
LEGACY_SPRD_AE_COMPENSATION_RANGE_MIN;
ae_compensation_param.ae_compensation_range[1] =
LEGACY_SPRD_AE_COMPENSATION_RANGE_MAX;
ae_compensation_param.ae_compensation_step_numerator =
LEGACY_SPRD_AE_COMPENSATION_STEP_NUMERATOR;
ae_compensation_param.ae_compensation_step_denominator =
LEGACY_SPRD_AE_COMPENSATION_STEP_DEMINATOR;
ae_compensation_param.ae_exposure_compensation =
controlInfo.ae_exposure_compensation;
} else {
ae_compensation_param.ae_compensation_range[0] =
controlInfo.ae_compensation_range[0];
ae_compensation_param.ae_compensation_range[1] =
controlInfo.ae_compensation_range[1];
ae_compensation_param.ae_compensation_step_numerator =
controlInfo.ae_compensation_step.numerator;
ae_compensation_param.ae_compensation_step_denominator =
controlInfo.ae_compensation_step.denominator;
ae_compensation_param.ae_exposure_compensation =
controlInfo.ae_exposure_compensation;
mManualExposureEnabled = true;
}
HAL_LOGD("cyy_CAMERA_PARAM_EXPOSURE_COMPENSATION:%d ==>%d", ae_compensation_param.ae_exposure_compensation, (cmr_uint)&ae_compensation_param);
SET_PARM(mHalOem, mCameraHandle, CAMERA_PARAM_EXPOSURE_COMPENSATION,
(cmr_uint)&ae_compensation_param);
break;
此部分重点是最后一句,SET_PARM函数 我们在SPRDCameraSettings中找到SET_PARM的定义
#define SET_PARM(h, x, y, z) \
do { \
LOGV("%s: set camera param: %s, %d", __func__, #x, y); \
if (NULL != h && NULL != h->ops) \
h->ops->camera_set_param(x, y, z); \
} while (0)
也就是说通过 mHalOem的ops,去调用camera_set_param,并传入后3个参数。
那么我们便要看看 mHalOem 是谁了,在SprdCamera3OEMIf.cpp中找到其赋值:
mHalOem = (oem_module_t *)malloc(sizeof(oem_module_t));
是 oem_module_t 类型的自定义结构体。
继续找
我们在crm_common.h找到结构体的定义
typedef struct oem_module {
uint32_t tag;
oem_ops_t *ops;
void *dso;
} oem_module_t;
果然,mHalOem中有一个oem_ops_t 类型的 ops 成员,继续追 oem_ops_t 结构体的定义: 就在当前cmr_common.h中定义该结构体,内容比较长,我们截取其中一部分来看:
typedef struct oem_ops {
cmr_int (*camera_init)(cmr_u32 camera_id, camera_cb_of_type callback,
void *client_data, cmr_uint is_autotest,
cmr_handle *camera_handle, void *cb_of_malloc,
void *cb_of_free);
cmr_int (*camera_deinit)(cmr_handle camera_handle);
cmr_int (*camera_release_frame)(cmr_handle camera_handle,
enum camera_data data, cmr_uint index);
cmr_int (*camera_set_param)(cmr_handle camera_handle,
enum camera_param_type id, uint64_t param);
cmr_int (*camera_start_preview)(cmr_handle camera_handle,
enum takepicture_mode mode);
cmr_int (*camera_stop_preview)(cmr_handle camera_handle);
cmr_int (*camera_start_autofocus)(cmr_handle camera_handle);
cmr_int (*camera_cancel_autofocus)(cmr_handle camera_handle);
cmr_int (*camera_cancel_takepicture)(cmr_handle camera_handle);
uint32_t (*camera_safe_scale_th)(void);
cmr_int (*camera_take_picture)(cmr_handle camera_handle,
enum takepicture_mode cap_mode);
} oem_ops_t;
oem_ops 是定义了一组指针函数,关于指针函数,有机会我们在单独写文章说明。 其中第四个是我们关心的 camera_set_param。
好了,到这里我们就找SprdCamera3OEMIf.cpp中SET_PARM函数的调用了,其实在看看SprdCamera3OEMIf.cpp中其他参数的设置,也都是通过SET_PARM在继续往下走的,所以我们只要把今天的AE_EXPOSURE参数设置的这条通路走通了,其他参数的设置也是类似的流程。
oem下
三,SprdOEMCamera.c 实现了 oem_ops_t 在上一步中,我们在cmr_common.h中找到了oem_ops_t的指针函数的定义,这些指针函数的实现是在SprdOEMCamera.c中的, SprdOEMCamera.c中定义的oem_ops_t 。这里的定义与上面cmr_common中的定义的函数是一样的。并且SprdOEMCamera.c还实现了每个函数。我们关注的是camera_set_param函数
static oem_ops_t oem_module_ops = {
camera_init, camera_deinit, camera_release_frame, camera_set_param,
camera_start_preview, camera_stop_preview, camera_start_autofocus,
camera_cancel_autofocus, camera_cancel_takepicture,
NULL, camera_take_picture, camera_get_sn_trim, camera_set_mem_func
};
SprdOEMCamera.c中camera_set_param的实现:
cmr_int camera_set_param(cmr_handle camera_handle, enum camera_param_type id,
uint64_t param) {
cmr_int ret = CMR_CAMERA_SUCCESS;
struct camera_context *cxt = (struct camera_context *)camera_handle;
struct setting_cmd_parameter setting_param;
if (!camera_handle) {
CMR_LOGE("camera handle is null");
ret = -CMR_CAMERA_INVALID_PARAM;
goto exit;
}
ret = camera_local_set_param(camera_handle, id, param);
exit:
return ret;
}
做了非空的判断后,有调用了camera_local_set_param方法,继续搜索该方法的实现。
四,cmr_oem.c 我们在oem下的cmr_oem.c中找到了 camera_local_set_param 的实现 该函数显示switch case了一部分type做了特殊处理,然后在default中实现,我们截取函数中的部分内容
cmr_int camera_local_set_param(cmr_handle oem_handle, enum camera_param_type id,
uint64_t param) {
cmr_int ret = CMR_CAMERA_SUCCESS;
struct camera_context *cxt = (struct camera_context *)oem_handle;
CHECK_HANDLE_VALID(oem_handle);
switch (id) {
case CAMERA_PARAM_FOCUS_RECT:
CMR_LOGD("set focus rect 0x%lx", param);
ret = cmr_focus_set_param(cxt->focus_cxt.focus_handle, cxt->camera_id,
id, (void *)param);
break;
case CAMERA_PARAM_SPRD_SUPER_MACROPHOTO_ENABLE: {
ret = camera_set_setting(oem_handle, id, param);
if (ret) {
CMR_LOGE("failed to set super macrophoto enable %ld", ret);
}
break;
}
case CAMERA_PARAM_3RD_3DNR_ENABLED: {
cxt->_3rd_3dnr_flag = param;
break;
}
case CAMERA_PARAM_SET_TOP_APP_ID: {
cxt->app_id = (enum top_app_id)param;
break;
}
default:
ret = camera_set_setting(oem_handle, id, param);
break;
}
if (ret) {
CMR_LOGE("failed to set param %ld", ret);
}
exit:
return ret;
}
对于我们当前跟踪的参数,是走到 default 中调用 camera_set_setting函数。
camera_set_setting也是上来 switch case参数类型,我们截取其中我们关注的部分,最后一条 case CAMERA_PARAM_EXPOSURE_COMPENSATION:
cmr_int camera_set_setting(cmr_handle oem_handle, enum camera_param_type id,
cmr_u64 param) {
cmr_int ret = CMR_CAMERA_SUCCESS;
struct camera_context *cxt = (struct camera_context *)oem_handle;
struct setting_cmd_parameter setting_param;
setting_param.camera_id = cxt->camera_id;
switch (id) {
case CAMERA_PARAM_FLASH:
case CAMERA_PARAM_ISP_FLASH:
setting_param.cmd_type_value = param;
ret = cmr_setting_ioctl(cxt->setting_cxt.setting_handle, id,
&setting_param);
break;
case CAMERA_PARAM_ANTIBANDING:
setting_param.cmd_type_value = param;
ret = cmr_setting_ioctl(cxt->setting_cxt.setting_handle, id,
&setting_param);
break;
case CAMERA_PARAM_EXPOSURE_COMPENSATION:
setting_param.ae_compensation_param =
*(struct cmr_ae_compensation_param *)param;
ret = cmr_setting_ioctl(cxt->setting_cxt.setting_handle, id,
&setting_param);
break;
default:
CMR_LOGI("don't support %d", id);
}
CMR_LOGV("X, ret=%ld", ret);
return ret;
}
我们看到,case CAMERA_PARAM_EXPOSURE_COMPENSATION:中继续调用了 cmr_setting_ioctl 函数。 继续搜索该函数的实现
五,cmr_setting.c 还是在oem下的 cmr_setting.c中搜到了
cmr_int cmr_setting_ioctl(cmr_handle setting_handle, cmr_uint cmd_type,
struct setting_cmd_parameter *parm) {
cmr_int ret = 0;
struct setting_component *cpt = (struct setting_component *)setting_handle;
if (!cpt || !parm || cmd_type >= SETTING_TYPE_MAX) {
CMR_LOGE("param has error cpt %p, parm %p, array_size %zu, "
"cmd_type %ld",
cpt, parm, cmr_array_size(setting_list), cmd_type);
return -CMR_CAMERA_INVALID_PARAM;
}
setting_ioctl_fun_ptr fun_ptr = cmr_get_cmd_fun_from_table(cmd_type);
if (fun_ptr) {
ret = (*fun_ptr)(cpt, parm);
} else {
CMR_LOGW("ioctl is NULL %ld", cmd_type);
}
return ret;
}
前面的判断部分先忽略,这里又使用了指针函数,通过 cmr_get_cmd_fun_from_table 去获取指针函数并调用。 cmr_get_cmd_fun_from_table的实现:
setting_ioctl_fun_ptr cmr_get_cmd_fun_from_table(cmr_uint cmd) {
if (cmd < SETTING_TYPE_MAX) {
return setting_list[cmd];
} else {
return NULL;
}
}
从setting_list数组中获取setting_ioctl_fun_ptr 类型的指针函数,setting_list是一个很长的数组,我们截取其中部分,重点关注我们本篇追踪的Ae曝光补偿参数:CAMERA_PARAM_EXPOSURE_COMPENSATION
static setting_ioctl_fun_ptr setting_list[SETTING_TYPE_MAX] = {
[CAMERA_PARAM_ZOOM] = setting_set_zoom_param,
[CAMERA_PARAM_REPROCESS_ZOOM_RATIO] =
setting_set_reprocess_zoom_ratio,
[CAMERA_PARAM_ENCODE_ROTATION] =
setting_set_encode_angle,
[CAMERA_PARAM_CONTRAST] = setting_set_contrast,
[CAMERA_PARAM_BRIGHTNESS] = setting_set_brightness,
[CAMERA_PARAM_AI_SCENE_ENABLED] =
setting_set_ai_scence,
[CAMERA_PARAM_SHARPNESS] = setting_set_sharpness,
[CAMERA_PARAM_WB] = setting_set_wb,
[CAMERA_PARAM_EFFECT] = setting_set_effect,
[CAMERA_PARAM_FLASH] = setting_set_flash_mode,
[CAMERA_PARAM_ANTIBANDING] = setting_set_antibanding,
[CAMERA_PARAM_FOCUS_RECT] = NULL,
[CAMERA_PARAM_AF_MODE] = NULL,
[CAMERA_PARAM_AUTO_EXPOSURE_MODE] =
setting_set_auto_exposure_mode,
[CAMERA_PARAM_ISO] = setting_set_iso,
[CAMERA_PARAM_EXPOSURE_COMPENSATION] =
setting_set_exposure_compensation,
};
我们在数组中找到了: [CAMERA_PARAM_EXPOSURE_COMPENSATION] = setting_set_exposure_compensation, 即通过cmr_get_cmd_fun_from_table函数得到的指针函数就是 :setting_set_exposure_compensation, 接下来在 cmr_setting_ioctl函数中就是调用 这个指针函数指向的函数了。
我们在当前cmr_setting.c中找到了 setting_set_exposure_compensation的实现。
setting_set_exposure_compensation(struct setting_component *cpt,
struct setting_cmd_parameter *parm) {
cmr_int ret = 0;
ret = setting_set_general(cpt, SETTING_GENERAL_EXPOSURE_COMPENSATION, parm);
return ret;
}
继续调用 setting_set_general函数,该函数也是上来就switch—case,我们把不相关的内容删去,只看我们关注的部分:
static cmr_int setting_set_general(struct setting_component *cpt,
enum setting_general_type type,
struct setting_cmd_parameter *parm) {
cmr_int ret = 0;
cmr_uint type_val = 0;
struct setting_hal_param *hal_param = get_hal_param(cpt, parm->camera_id);
struct setting_general_item *item = NULL;
item = &general_list[type];
switch (type) {
case SETTING_GENERAL_AUTO_EXPOSURE_MODE:
type_val = parm->ae_param.mode;
break;
case SETTING_GENERAL_EXPOSURE_COMPENSATION:
if (setting_is_active(cpt)) {
if (setting_is_rawrgb_format(cpt, parm)) {
ret = setting_isp_ctrl(cpt, item->isp_cmd, parm);
}
}
hal_param->hal_common.ae_compensation_param =
parm->ae_compensation_param;
break;
default:
type_val = parm->cmd_type_value;
break;
}
return ret;
}
case SETTING_GENERAL_EXPOSURE_COMPENSATION中闯过两个if判断,关键点在调用 setting_isp_ctrl 函数。
该函数仍在当前c文件中实现的,我们还是去掉不相关内容:
static cmr_int setting_isp_ctrl(struct setting_component *cpt, cmr_uint isp_cmd,
struct setting_cmd_parameter *parm) {
cmr_int ret = 0;
struct setting_init_in *init_in = &cpt->init_in;
struct common_isp_cmd_param isp_param;
struct setting_hal_param *hal_param = NULL;
if (init_in->setting_isp_ioctl) {
isp_param.camera_id = parm->camera_id;
if(COM_ISP_SET_EXPOSURE_TIME == isp_cmd) {
parm->cmd_type_value = parm->cmd_type_value * 1000;
}
CMR_LOGD("cmd_type_value=%"PRIu64"",parm->cmd_type_value);
camera_param_to_isp(isp_cmd, parm, &isp_param);
ret = (*init_in->setting_isp_ioctl)(init_in->oem_handle, isp_cmd,
&isp_param);
if (ret) {
CMR_LOGE("sn ctrl failed");
}
parm->cmd_type_value = isp_param.cmd_value;
}
return ret;
}
关键在指针函数:(*init_in->setting_isp_ioctl) 的调用,即 setting_init_in 类型init_in对象下的 setting_isp_ioctl指针函数的指向。 我们搜索setting_isp_ioctl的赋值,要找到setting_isp_ioctl指向的函数。 在cmr_oem.c我们找到了对 setting_init_in的赋值
cmr_int camera_setting_init(cmr_handle oem_handle) {
ATRACE_BEGIN(__FUNCTION__);
cmr_int ret = CMR_CAMERA_SUCCESS;
struct camera_context *cxt = (struct camera_context *)oem_handle;
struct setting_context *setting_cxt = NULL;
struct setting_init_in init_param;
CHECK_HANDLE_VALID(oem_handle);
setting_cxt = &cxt->setting_cxt;
CHECK_HANDLE_VALID(setting_cxt);
if (1 == setting_cxt->inited) {
CMR_LOGD("setting has been de-intialized");
goto exit;
}
init_param.oem_handle = oem_handle;
init_param.camera_id_bits = (1 << cxt->camera_id);
init_param.io_cmd_ioctl = camera_ioctl_for_setting;
init_param.setting_sn_ioctl = camera_sensor_ioctl;
init_param.setting_isp_ioctl = camera_isp_ioctl;
init_param.get_setting_activity = camera_get_setting_activity;
init_param.before_set_cb = camera_before_set;
init_param.after_set_cb = camera_after_set;
init_param.padding = 0;
ret = cmr_setting_init(&init_param, &setting_cxt->setting_handle);
if (ret) {
CMR_LOGE("failed to init setting %ld", ret);
ret = -CMR_CAMERA_NO_SUPPORT;
goto exit;
}
setting_cxt->inited = 1;
exit:
CMR_LOGD("X,ret=%ld", ret);
ATRACE_END();
return ret;
}
其中 init_param.setting_isp_ioctl = camera_isp_ioctl; 是将setting_isp_ioctl 指向了 camera_isp_ioctl函数,精简后的 camera_isp_ioctl函数内容如下:
cmr_int camera_isp_ioctl(cmr_handle oem_handle, cmr_uint cmd_type,
struct common_isp_cmd_param *param_ptr) {
switch (cmd_type) {
case COM_ISP_SET_EXPOSURE_TIME:
CMR_LOGD("exposure time %" PRIu64 "", param_ptr->cmd_value);
isp_cmd = ISP_CTRL_SET_AE_EXP_TIME;
isp_param = param_ptr->cmd_value;
cxt->exp_time = isp_param;
break;
default:
CMR_LOGE("don't support cmd %ld", cmd_type);
ret = CMR_CAMERA_NO_SUPPORT;
break;
}
if (set_isp_flag) {
ret = isp_ioctl(isp_cxt->isp_handle, isp_cmd, (void *)&isp_param);
if (ret) {
CMR_LOGE("failed isp ioctl %ld", ret);
} else if (COM_ISP_SET_ISO == cmd_type) {
if (0 == param_ptr->cmd_value) {
isp_capability(isp_cxt->isp_handle, ISP_CUR_ISO,
(void *)&isp_param);
cxt->setting_cxt.is_auto_iso = 1;
} else {
cxt->setting_cxt.is_auto_iso = 0;
}
isp_param = POWER2(isp_param - 1) * ONE_HUNDRED;
CMR_LOGI("auto iso %d, exif iso %d",
cxt->setting_cxt.is_auto_iso, isp_param);
} else if (COM_ISP_SET_SENSITIVITY == cmd_type) {
if (0 == param_ptr->cmd_value) {
isp_capability(isp_cxt->isp_handle, ISP_CUR_ISO,
(void *)&isp_param);
cxt->setting_cxt.is_auto_iso = 1;
} else {
cxt->setting_cxt.is_auto_iso = 0;
}
CMR_LOGI("auto iso %d, exif iso %d",
cxt->setting_cxt.is_auto_iso, isp_param);
}
}
exit:
CMR_LOGV("X, ret=%ld", ret);
return ret;
}
case COM_ISP_SET_EXPOSURE_TIME: 之后调用 isp_ioctl函数。
继续搜索 isp_ioctl 函数的实现
**
ISP 模块
**
六,isp_mw.c 我们找到 isp_ioctl 函数的实现是在 isp_mw.c中
cmr_int isp_ioctl(cmr_handle handle, enum isp_ctrl_cmd cmd, void *param_ptr)
{
cmr_int ret = ISP_SUCCESS;
struct isp_mw_context *cxt = (struct isp_mw_context *)handle;
ret = isp_alg_fw_ioctl(cxt->alg_fw_handle, cmd, param_ptr);
pthread_mutex_unlock(&cxt->isp_mw_mutex);
ISP_TRACE_IF_FAIL(ret, ("fail to do isp_ioctl"));
return ret;
}
isp_ioctl 函数继续调用 isp_alg_fw_ioctl 函数
七,isp_alg_fw.c
cmr_int isp_alg_fw_ioctl(cmr_handle isp_alg_handle, enum isp_ctrl_cmd io_cmd, void *param_ptr)
{
cmr_int ret = ISP_SUCCESS;
struct isp_alg_fw_context *cxt = (struct isp_alg_fw_context *)isp_alg_handle;
enum isp_ctrl_cmd cmd = io_cmd & 0x7fffffff;
isp_io_fun io_ctrl = NULL;
cmr_u32 loop = 1000, cnt = 0, time_out = 0;
cmr_u32 is_sync_ai = 0, is_aysnc_ai = 0, is_ai_cmd = 0, *msg_data;
cmr_u8 *wait_status;
CMR_MSG_INIT(message);
cxt->commn_cxt.isp_callback_bypass = io_cmd & 0x80000000;
io_ctrl = isp_ioctl_get_fun(cmd);
if (NULL != io_ctrl) {
wait_status = (is_ai_cmd ? &cxt->ai_init_status : &cxt->init_status);
while (*wait_status== FW_INIT_GOING) {
ISP_LOGD("cam%ld cmd %d wait init done %d\n", cxt->camera_id, cmd, cnt);
usleep(1 * 1000);
if (cnt++ >= loop) {
time_out = 1;
break;
}
}
if (*wait_status == FW_INIT_ERR || time_out) {
ISP_LOGE("cam%ld fw init error or time out %d\n", cxt->camera_id, time_out);
return ISP_ERROR;
}
ret = io_ctrl(cxt, param_ptr);
} else {
ISP_LOGV("io_ctrl fun is null, cmd %d", cmd);
}
if (NULL != cxt->commn_cxt.callback) {
cxt->commn_cxt.callback(cxt->commn_cxt.caller_id,
ISP_CALLBACK_EVT | ISP_CTRL_CALLBACK | cmd, NULL, ISP_ZERO);
}
return ret;
}
isp_alg_fw_ioctl函数继续调用 isp_ioctl_get_fun,继续追踪该函数的实现。
八,isp_ioctrl.c 我们在 isp_ioctrl.c中找到了 isp_ioctl_get_fun 函数的实现
static isp_io_fun isp_ioctl_get_fun(enum isp_ctrl_cmd cmd)
{
isp_io_fun io_ctrl = NULL;
cmr_u32 total_num = 0;
cmr_u32 i = 0;
total_num = sizeof(s_isp_io_ctrl_fun_tab) / sizeof(struct isp_io_ctrl_fun);
for (i = 0; i < total_num; i++) {
if (cmd == s_isp_io_ctrl_fun_tab[i].cmd) {
io_ctrl = s_isp_io_ctrl_fun_tab[i].io_ctrl;
break;
}
}
return io_ctrl;
}
又看到了for循环遍历数组,我们前面遇到过,就是从数组里面查找对应参数调用的方法。 我们来看下s_isp_io_ctrl_fun_tab的内容,果然又是一堆的key-value形式的定义,我们只截取其中关注的部分:
static struct isp_io_ctrl_fun s_isp_io_ctrl_fun_tab[] = {
{ISP_CTRL_AE_MEASURE_LUM, ispctl_ae_measure_lum},
{ISP_CTRL_EV, ispctl_ev},
{ISP_CTRL_AE_EXP_COMPENSATION, ispctl_ae_exp_compensation},
{ISP_CTRL_MAX, NULL}
};
找到了ISP_CTRL_AE_EXP_COMPENSATION对应的函数是 ispctl_ae_exp_compensation
static cmr_int ispctl_ae_exp_compensation(cmr_handle isp_alg_handle, void *param_ptr)
{
cmr_int ret = ISP_SUCCESS;
struct isp_alg_fw_context *cxt = (struct isp_alg_fw_context *)isp_alg_handle;
struct isp_exp_compensation *exp_compensation = (struct isp_exp_compensation *)param_ptr;
struct ae_exp_compensation exp_comp;
if (NULL == exp_compensation) {
return ISP_PARAM_NULL;
}
exp_comp.comp_range.min = exp_compensation->comp_range.min;
exp_comp.comp_range.max = exp_compensation->comp_range.max;
exp_comp.comp_val = exp_compensation->comp_val;
exp_comp.step_numerator = exp_compensation->step_numerator;
exp_comp.step_denominator = exp_compensation->step_denominator;
if (cxt->ops.ae_ops.ioctrl) {
ret = cxt->ops.ae_ops.ioctrl(cxt->ae_cxt.handle, AE_SET_EXPOSURE_COMPENSATION, &exp_comp, NULL);
}
return ret;
}
这里重点就是调用 cxt->ops.ae_ops.ioctrl,我们要追踪下这个isp_alg_fw_context 类型的ctx是什么,然后在进一步查看ops对象 和 ioctrl函数调用了什么。
isp_alg_fw_context 这个结构体的定义在 isp_alg_fw.c中,内容比较多,此处只看下ops 是什么类型的。
struct isp_alg_fw_context{
.....
struct ispalg_lib_ops ops;
.....
}
struct ispalg_lib_ops {
struct ispalg_ae_ctrl_ops ae_ops;
struct ispalg_af_ctrl_ops af_ops;
struct ispalg_afl_ctrl_ops afl_ops;
struct ispalg_awb_ctrl_ops awb_ops;
struct ispalg_smart_ctrl_ops smart_ops;
struct ispalg_pdaf_ctrl_ops pdaf_ops;
struct ispalg_lsc_ctrl_ops lsc_ops;
struct ispalg_tof_ctrl_ops tof_ops;
struct ispalg_ai_ctrl_ops ai_ops;
};
struct ispalg_ae_ctrl_ops {
cmr_s32 (*init)(struct ae_init_in *input_ptr, cmr_handle *handle_ae, cmr_handle result);
cmr_int (*deinit)(cmr_handle *isp_afl_handle);
cmr_int (*process)(cmr_handle handle_ae, struct ae_calc_in *in_ptr, struct ae_calc_out *result);
cmr_int (*ioctrl)(cmr_handle handle, enum ae_io_ctrl_cmd cmd, cmr_handle in_ptr, cmr_handle out_ptr);
};
ioctrl又是一个指针函数,在搜下这个指针函数的赋值,在当前isp_alg_fw.c的文件中,我们找到了ispalg_load_library函数,是给ops结构体下所有对象赋值,截取其中一部分来看:
static cmr_int ispalg_load_library(cmr_handle adpt_handle)
{
cmr_int ret = ISP_SUCCESS;
struct isp_alg_fw_context *cxt = (struct isp_alg_fw_context *)adpt_handle;
ISP_LOGD("cam%ld start\n", cxt->camera_id);
cxt->ops.ae_ops.init = dlsym(cxt->ispalg_lib_handle, "ae_ctrl_init");
if (!cxt->ops.ae_ops.init) {
ISP_LOGE("fail to dlsym ae_ops.init");
goto error_dlsym;
}
cxt->ops.ae_ops.deinit = dlsym(cxt->ispalg_lib_handle, "ae_ctrl_deinit");
if (!cxt->ops.ae_ops.deinit) {
ISP_LOGE("fail to dlsym ae_ops.deinit");
goto error_dlsym;
}
cxt->ops.ae_ops.process = dlsym(cxt->ispalg_lib_handle, "ae_ctrl_process");
if (!cxt->ops.ae_ops.process) {
ISP_LOGE("fail to dlsym ae_ops.process");
goto error_dlsym;
}
cxt->ops.ae_ops.ioctrl = dlsym(cxt->ispalg_lib_handle, "ae_ctrl_ioctrl");
if (!cxt->ops.ae_ops.ioctrl) {
ISP_LOGE("fail to dlsym ae_ops.ioctrl");
goto error_dlsym;
}
return ret;
}
终于见到真章了,这个通过dlsym去调用lib库中的函数,
|