开机时camera设置
在介绍spreadtrum或者说unisoc camera hal preview流程前,需要先看一下sprdcamera::SprdCamera3Factory::get_number_of_cameras和sprdcamera::SprdCamera3Factory::get_camera_info,这两个函数是在开机过程中执行的,get_number_of_cameras主要是根据sensor_config.xml中配置的camera name和af、otp、sensor_id等进行物理上的扫描,看实际的机器上配置了多少个camera,需要关注的重点是identify过程中对实际sensor i2c读写,以及otp读取
具体的流程如下图:
依次看一下sensor_drv_u.c里调用的几个函数
- sensor_drv_xml_load_file这个函数只要是调用xmlParseFile和xmlDocGetRootElement分别打开获得文件节点和xml文件的根节点
- sensor_drv_xml_get_node_num获取名称为CameraModuleCfg的节点数,实际就是配置的camera number
- sensor_drv_xml_get_node调用具体的节点
- sensor_drv_xml_parse_camera_module_info获取具体camera配置信息
- sensor_context_init这个函数没有画在图中,具体是打开底层的设备节点/dev/sprd_sensor,这样后面就可以根据具体的sensor id读取具体的i2c设备
- sensor_drv_identify 通过读取camera pid和vendor id来确定camera是否正确
- sensor_drv_load_library根据之前xml读取到的camera name,打开相应的so库,如libsensor_s5kgm1st.so,并通过dlsym获取的s5kgm1st sensor driver中的配置和获取camera info的指针sensor_info_ptr,后去配置gain,shutter以及otp,都需要通过这个接口
- sensor_drv_ic_identify中sensor_get_module_cfg_info和sensor_ic_create都是初始化sensor_cxt,i2c初始化后power on ,sns_ops->identify调用camera sensor driver中的s5kgm1st_drv_identify通过i2c读取id并比较
- sensor_drv_create_phy_sensor_info 将具体sensor max width/height、image format、sensor type等信息保存在phy_sensor_info_list结构体中,后面会多次用到
接下来看一下SprdCamera3Factory::getCameraInfo,这一块涉及到一些参数配置,和camera界面上的设置相关
- SprdCamera3Setting::getSensorStaticInfo将phy_sensor_info_list中获取到的信息赋值给全局变量
- SprdCamera3Setting::initDefaultParameters一些参数设置,暂时不关注
- SprdCamera3Setting::getStaticMetadata
- initStaticParameters设置color、edge、lens_info、flash_info、scaler_info…信息,其中调用initStaticParametersforScalerInfo设置largest_sensor_w、largest_sensor_h,如果CONFIG_CAMERA_AUTO_DETECT_SENSOR配置了,则取sensor driver中的的max size,否则取值为default_sensor_max_sizes列表中的
- initStaticParametersforSensorInfo 设置一些sensor info,暂时不用关注
camera hal open流程
如下流程图
需要关注的是
- camera_sensor_init 这个过程和开机是执行的getnumberofcamera流程类似,这里不再细讲
- camera_grab_init
cmr_int camera_grab_init(cmr_handle oem_handle)
{
ret = cmr_grab_init(&grab_param, &grab_handle); //grab 的初始化
cmr_grab_stream_cb(grab_handle, camera_sensor_streamctrl); //对流的一个控制, 便于在执行 preview、 focus 等操作时执行 stream on 操作, 开启数据传输, 往 buffer 里面写数据。
}
cmr_int cmr_grab_init(struct grab_init_param *init_param_ptr, cmr_handle
*grab_handle)
{
ret = cmr_grab_create_thread((cmr_handle)p_grab);
}
static cmr_int cmr_grab_create_thread(cmr_handle grab_handle)
{
ret = pthread_create(&p_grab->thread_handle, &attr,cmr_grab_thread_proc, (void*)grab_handle);}//便于在后续执行 preview、 snapshot 等操作时读取底层 buffer。
static void* cmr_grab_thread_proc(void* data)
{
//从底层不断的读取 buffer, 具体读取 buffer 的动作在 kernel 里面执行, 如果有数据产生, 就会相应中断, 就开始不断读取底层 buffer 中的数据 填充一个 buffer, 会有一个 TX_DONE 的中断上来, 从而激活 oem 层的控制线程该线程会调到 HWI 的接口显示此帧数据。
while(1) {
op.cmd = SPRD_IMG_GET_FRM_BUFFER;
if (-1 == read(p_grab->fd, &op, sizeof(struct sprd_img_read_op))) {
CMR_LOGI("Failed to read frame buffer");
break;
}
}
- camera_res_init
static cmr_int camera_res_init_internal(cmr_handle oem_handle) {
cmr_int ret = CMR_CAMERA_SUCCESS;
CMR_PRINT_TIME;
struct camera_context *cxt = (struct camera_context *)oem_handle;
/* for multicamera mode,when open convered sensor,only need to init setting
*/
if (CONVERED_CAMERA_INIT) {
ret = camera_setting_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init setting %ld", ret);
}
goto exit;
}
ret = camera_ipm_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init ipm %ld", ret);
goto exit;
}
ret = camera_setting_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init setting %ld", ret);
goto exit;
}
ret = camera_focus_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init focus %ld", ret);
goto exit;
}
// move it to front before isp init,because iommu flag need check through
// grab_handle
#if 0
ret = camera_grab_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init grab %ld", ret);
goto exit;
}
#endif
ret = camera_scaler_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init scaler %ld", ret);
goto exit;
}
ret = camera_rotation_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init rotation %ld", ret);
goto exit;
}
ret = camera_preview_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init preview %ld", ret);
goto exit;
}
ret = camera_snapshot_init(oem_handle);
if (ret) {
CMR_LOGE("failed to init snapshot %ld", ret);
goto exit;
} else {
// CMR_LOGI("init mds ok");
ret = camera_init_thread(oem_handle);
}
exit:
if (ret) {
camera_res_deinit_internal(oem_handle);
}
return ret;
}
- ipm init:调用 cmr_ipm.c 的 cmr_ipm_init()函数执行 ipm init 操作,分配ipm 句柄所需要的空间,该模块没有创建消息处理线程
- setting init:调用 cmr_setting.c 的 cmr_setting_init()函数执行 setting init操作,创建 setting 模块的消息处理线程,该线程处理函数为setting_thread_proc(),该线程处理函数主要执行的是 zoom 参数的处理
- focus init:调用 cmr_focus.c 的 cmr_focus_init()函数执行 focus init 操作,创建 AF 模块的消息处理线程,该线程处理函数为 af_thread_pro()
- scaler init:调用 cmr_scale.c 的 cmr_scale_open()函数执行 scaler init 操作,该函数首先 open scaler device;之后创建 scaler 模块的消息处理线程,该线程处理函数为 cmr_scale_thread_proc;
- rotation init:调用 cmr_rotate.c 的 cmr_rot_open()函数执行 rotation init操作,该函数只执行 open rotate device 的操作
- preview init
cmr_int camera_preview_init(cmr_handle oem_handle) { struct preview_init_param init_param; //首先会将预览用到的外部接口操作进行匹配 ret = cmr_preview_init(&init_param, &prev_cxt->preview_handle); } struct preview_init_param { cmr_uint sensor_bits;//要打开的 sensor 设备集 preview_cb_func oem_cb;////OEM 提供的回调函数 cmr_handle oem_handle;//OEM 句柄 struct preview_md_ops ops;//预览模块用到的外部接口操作集合 void* private_data;//私有数据指针 } ; cmr_int cmr_preview_init(struct preview_init_param *init_param_ptr,cmr_handle *preview_handle_ptr) { //A、 申请内存保存参数。 //B、 创建线程 ret = prev_create_thread(handle); //C、 创建回传线程 ret = prev_create_cb_thread(handle); } B、 创建线程 cmr_int prev_create_thread(struct prev_handle *handle) { ret = cmr_thread_create(&handle→ thread_cxt.assist_thread_handle,PREV_MSG_QUEUE_SIZE,prev_assist_thread_proc,(void*)handle);//主要负责 preview 流程所需的 buffer 以及启动 FD 的操作。 ret = cmr_thread_create(&handle→ thread_cxt.thread_handle,PREV_MSG_QUEUE_SIZE,prev_thread_proc,(void*)handle);//主要负责 preview 操作控制的流程。 //发送消息给 prev_thread_proc 这个线程, 用于启动 preview。 当收到这个消息之后会执行 cmr_int prev_local_init(struct prev_handle *handle)这个函数, 从而启动 preview。 message.msg_type = PREV_EVT_INIT; message.sync_flag = CMR_MSG_SYNC_RECEIVED; ret = cmr_thread_msg_send(handle->thread_cxt.thread_handle,&message); } C、 创建回传线程。 cmr_int prev_create_cb_thread(struct prev_handle *handle) { ret =cmr_thread_create(&handle-thread_cxt.cb_thread_handle,PREV_MSG_QUEUE_SIZE,prev_cb_thread_proc,(void*)handle);//负责向 camera OEM 模块发送 preview 消息和数据的 }
- snapshot init : 调 用 cmr_snapshot.c 的 cmr_snapshot_init() 函 数 执 行snapshot init 操作,该函数需要创建多个线程:用于拍照后处理操作控制和停止拍照后处理的线程,线程处理函数 snp_main_thread_proc();负责接收拍照数据并开始处理操作的线程,线程处理函数 snp_postproc_thread_proc();负责向Camera OEM 模块发送消息的线程,线程处理函数 snp_notify_thread_proc();负责处理外部模块和内部模块回调函数的线程,线程处理函数snp_proc_cb_thread_proc();负责向 Camera OEM 模块发送拍照消息的线程,线程处理函数 snp_secondary_thread_proc();负责数据格式转换,如RAW->YUV 的线程,线程处理函数为 snp_cvt_thread_proc();负责拍照回显处理 的 线 程 , 线 程 处 理 函 数 为 snp_redisplay_thread_proc() ; 负 责thumbnail 以 及 thumbnail encode 的线程,线程处理函数为snp_thumb_thread_proc();负责生成完整 jpeg 码流的线程,线程处理函数为snp_write_exif_thread_proc()