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 mode
            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 {
            // standard implementation following android api
            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函数
我们在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的分层及设计思想还需要我们进一步去研究,我们一起加油呀!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值