Camera HAL 参数传递流程 ---- 以ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION为例追踪

本文主要是介绍Camera HAL 参数传递流程 ---- 以ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION为例追踪,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CameraApp里面用户操作的设置项分为两类:

  • 一类由App自行处理,比如照片保存路径、绘制九宫格参照线、拍照声音等等
  • 一类需要经由framework下发到hal,然后进一步流转到相应的算法库中去处理

本篇我们以用户设置AE补偿参数为例,来跟踪第二种情况下的参数设置流程。
代码路径:vendor\sprd\modules\libcamera

涉及模块:hal----》oem----》isp

我们先给出整个流程的时序图,方便大家现有一个整体的认识,然后在分析具体每个步骤的代码。在这里插入图片描述

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) {// just for legacy sprd isp ae compensation manual modeae_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 {// standard implementation following android apiae_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函数
我们在SprdCamera3Settings.h中找到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;/** Modules methods */oem_ops_t *ops;/** module's dso */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在继续往下走的,所以j今天我们只要把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,// camera_safe_scale_th,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中实现未匹配case的操作,我们截取函数中的部分内容:

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, /*by focus module*/[CAMERA_PARAM_AF_MODE] = NULL,    /*by focus module*/[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;.....
}
//ops 的结构体 ispalg_lib_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;
};
//ae_ops 的结构体 ispalg_ae_ctrl_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库中的函数。
所以我们从isp_ioctrl.c中ispctl_ae_exp_compensation函数追过来的最终调用是到lib库中去了。

到此,我们追到了从最初hal下的SprdCamera3Setting.c接受上层参数,到将参数传递给闭源的lib库函数的流程,其中涉及到了hal、oem、isp模块,并伴随大量的结构体出现。流程追完了,但是整个libcamera的分层及设计思想还需要我们进一步去研究,我们一起加油呀!

这篇关于Camera HAL 参数传递流程 ---- 以ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION为例追踪的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/997069

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除