[SPRD CAMERA] 5 HAL Camera open流程二

open流程一主要是沿着open的主线一直到sensor open,着一些主要是看看 camera_init_internal 中的其他初始化流程

cmr_int camera_init_internal(cmr_handle oem_handle, cmr_uint is_autotest) {
	···
	//sensor初始化
	ret = camera_sensor_init(oem_handle, is_autotest);

	//grab初始化
	ret = camera_grab_init(oem_handle);

	//res初始化
	ret = camera_res_init(oem_handle);

	//isp初始化
	ret = camera_isp_init(oem_handle);

	//初始化完成
	ret = camera_res_init_done(oem_handle);

	//前置摄像头,lcd屏幕可以作为补光灯
	camera_front_lcd_enhance_module_init(oem_handle);
	···
	return ret;
}

书接上篇我们分析了camera_sensor_init这个函数,下面我们对其他的初始化流程分析。

1、camera_grab_init

这个主要时图形数据的传输

idh.code\vendor\sprd\modules\libcamera\oem2v6\src\cmr_oem.c

cmr_int camera_grab_init(cmr_handle oem_handle) {
    struct phySensorInfo *phyPtr = NULL;
    cmr_int ret = CMR_CAMERA_SUCCESS;
    struct camera_context *cxt = (struct camera_context *)oem_handle;
    struct grab_context *grab_cxt = NULL;
    struct sensor_context *sn_cxt = NULL;
    cmr_handle grab_handle = NULL;
    struct grab_init_param grab_param;
    struct sensor_exp_info sensor_info;
    cmr_bzero(&sensor_info, sizeof(struct sensor_exp_info));
    grab_cxt = &cxt->grab_cxt;
    sn_cxt = &(cxt->sn_cxt);

    ret = cmr_sensor_get_info(sn_cxt->sensor_handle, cxt->camera_id,
                              &(sn_cxt->sensor_info));

    phyPtr = sensorGetPhysicalSnsInfo(cxt->camera_id);

    if (0 == grab_cxt->inited) {
        grab_param.oem_handle = oem_handle;
        grab_param.sensor_id = phyPtr->slotId;
        ret = cmr_grab_init(&grab_param, &grab_handle);
        if (ret) {
            CMR_LOGE("failed to init grab %ld", ret);
            ret = -CMR_CAMERA_NO_SUPPORT;
            goto exit;
        }
        cmr_grab_evt_reg(grab_handle, camera_grab_evt_cb);
            //p_grab->grab_evt_cb = grab_event_cb;
        cmr_grab_stream_cb(grab_handle, camera_sensor_streamctrl);
            //p_grab->stream_on_cb = str_on(camera_sensor_streamctrl)
        /*only raw sensor should init isp*/
        if (CAM_IMG_FMT_BAYER_MIPI_RAW == sn_cxt->sensor_info.image_format) {	
            cmr_grab_isp_statis_evt_reg(grab_handle, isp_statis_evt_cb);
                //p_grab->isp_statis_evt_cb = isp_statis_event_cb;
            cmr_grab_isp_irq_proc_evt_reg(grab_handle, isp_irq_proc_evt_cb);
                //p_grab->isp_irq_proc_evt_cb = isp_irq_proc_event_cb;
        }
        cmr_grab_post_ynr_evt_reg(grab_handle, camera_grab_post_ynr_evt_cb);
            //p_grab->grab_post_ynr_evt_cb = grab_post_ynr_evt_cb;
        grab_cxt->inited = 1;
        grab_cxt->grab_handle = grab_handle;
    }

    return ret;
}

这个函数我们主要是初始化 grab_handle,包含各种回调。回调函数的调用时在cmr_grab_init中的线程调用的。

这里我们先看cmr_grab_init函数

idh.code\vendor\sprd\modules\libcamera\oem2v6\src\cmr_grab.c

cmr_int cmr_grab_init(struct grab_init_param *init_param_ptr,
                      cmr_handle *grab_handle) {
    cmr_int ret = 0;
    cmr_u32 i = 0;
    cmr_u32 channel_id;
    struct cmr_grab *p_grab = NULL;
    struct sprd_img_res res;

    p_grab = (struct cmr_grab *)malloc(sizeof(struct cmr_grab));

    p_grab->init_param = *init_param_ptr;
    p_grab->fd = open(CMR_GRAB_DEV_NAME, O_RDWR, 0);
    //#define CMR_GRAB_DEV_NAME "/dev/sprd_image"

    ret = pthread_mutex_init(&p_grab->cb_mutex, NULL);
    ret = pthread_mutex_init(&p_grab->dcam_mutex, NULL);
    ret = pthread_mutex_init(&p_grab->status_mutex, NULL);

    for (channel_id = 0; channel_id < CHN_MAX; channel_id++) {
        ret = pthread_mutex_init(&p_grab->path_mutex[channel_id], NULL);
    }

    pthread_mutex_lock(&p_grab->dcam_mutex);
    if (0 == p_grab->mode_enable) {
        res.sensor_id = p_grab->init_param.sensor_id;
        ret = ioctl(p_grab->fd, SPRD_IMG_IO_GET_DCAM_RES, &res);
        //获取一些dcam的信息,具体分析等分析驱动时在说
        p_grab->res = res.flag;
        p_grab->mode_enable = 1;
    }
    pthread_mutex_unlock(&p_grab->dcam_mutex);

    sem_init(&p_grab->close_sem, 0, 0);
    ret = cmr_grab_create_thread((cmr_handle)p_grab);
            //pthread_create(&p_grab->thread_handle, &attr, cmr_grab_thread_proc, (void *)grab_handle);
            //这里创建一个线程用来读取/dev/sprd_image,根据读取额数据调用对应的回调函数
    p_grab->grab_evt_cb = NULL;
    p_grab->stream_on_cb = NULL;
    p_grab->isp_cb_enable = 1;
    memset(p_grab->chn_status, 0, sizeof(p_grab->chn_status));
    *grab_handle = (cmr_handle)p_grab;

    return ret;
}

这里时初始化grab_handle结构体,同时启动一个线程。

static void *cmr_grab_thread_proc(void *data) {
    cmr_s32 evt_id = -1;
    struct frm_info frame;
    cmr_u32 on_flag = 0;
    cmr_s32 frm_num = -1;
    cmr_s32 cnt;
    struct cmr_grab *p_grab;
    struct img_data_end endian;
    struct sprd_img_read_op op;
    struct sprd_img_res res;
    struct sprd_img_statis_info statis_info;
    struct sprd_irq_info irq_info;

    p_grab = (struct cmr_grab *)data;

    struct camera_context *cxt = (struct camera_context *)p_grab->init_param.oem_handle;

    while (1) {
        cnt = sizeof(struct sprd_img_read_op);
        op.cmd = SPRD_IMG_GET_FRM_BUFFER;
        op.sensor_id = p_grab->init_param.sensor_id;
        if (cnt != read(p_grab->fd, &op, sizeof(struct sprd_img_read_op))) {
            CMR_LOGE("read failed");
            break;
        }

        if (IMG_TX_STOP == op.evt) {
            // stopped , to do release resource
            CMR_LOGI("TX Stopped, exit thread");
            break;
        } else if (IMG_SYS_BUSY == op.evt) {
            CMR_LOGI("continue");
            continue;
        } else {
            if (op.parm.frame.irq_type == CAMERA_IRQ_IMG ||
                op.parm.frame.irq_type == CAMERA_IRQ_4IN1_DONE) {
                if (p_grab->grab_evt_cb) {
                     (*p_grab->grab_evt_cb)(
                         evt_id, &frame,
                         (void *)p_grab->init_param.oem_handle);
                }
            } else if (op.parm.frame.irq_type == CAMERA_IRQ_STATIS) {      
                if (p_grab->isp_statis_evt_cb && p_grab->isp_cb_enable) {
                    (*p_grab->isp_statis_evt_cb)(
                        evt_id, &statis_info, (void *)cxt->isp_cxt.isp_handle);
                }
            } else if (op.parm.frame.irq_type == CAMERA_IRQ_DONE) {
                if (p_grab->isp_irq_proc_evt_cb && p_grab->isp_cb_enable) {
					CMR_LOGV("irq_info.irq_property = %d",irq_info.irq_property);
                    (p_grab->isp_irq_proc_evt_cb)(
                        evt_id, &irq_info, (void *)cxt->isp_cxt.isp_handle);
                }
            } else if (op.parm.frame.irq_type == CAMERA_IRQ_POST_YNR_DONE) {
                if (p_grab->grab_post_ynr_evt_cb && p_grab->isp_cb_enable) {
                    (p_grab->grab_post_ynr_evt_cb)(
                        evt_id, NULL, (void *)p_grab->init_param.oem_handle);
                }
            }
        }
    }

    return NULL;
}

这里在循环的读取sprd_image节点,根据读取出来的数据类型和中断类型调用不同的回调函数。我们的帧数就是这里从这里开始向上传递的,后面单独介绍帧数据流程。

2、camera_res_init

idh.code\vendor\sprd\modules\libcamera\oem2v6\src\cmr_oem.c

cmr_int camera_res_init(cmr_handle oem_handle) {
    cmr_int ret = CMR_CAMERA_SUCCESS;
    struct camera_context *cxt = (struct camera_context *)oem_handle;
    CMR_MSG_INIT(message);

    CMR_PRINT_TIME;

    sem_init(&cxt->hdr_sync_sm, 0, 0);
    sem_init(&cxt->hdr_flag_sm, 0, 1);

    sem_init(&cxt->threednr_flag_sm, 0, 1);

    sem_init(&cxt->cnr_flag_sm, 0, 1);
    sem_init(&cxt->dre_flag_sm, 0, 1);

    sem_init(&cxt->ai_scene_flag_sm, 0, 1);

    sem_init(&cxt->filter_sm, 0, 1);

    sem_init(&cxt->share_path_sm, 0, 0);
    sem_init(&cxt->access_sm, 0, 1);
    sem_init(&cxt->sbs_sync_sm, 0, 0);

    cxt->err_code = CMR_CAMERA_SUCCESS;
    /*create thread*/
    ret = cmr_thread_create((cmr_handle *)&cxt->init_thread,
                            CAMERA_OEM_MSG_QUEUE_SIZE, camera_init_thread_proc,
                            (void *)cxt);

    ret = cmr_thread_set_name(cxt->init_thread, "res_init");

    message.msg_type = CMR_EVT_INIT;
    message.sync_flag = CMR_MSG_SYNC_NONE;
    ret = cmr_thread_msg_send(cxt->init_thread, &message);

    return ret;
}

这个函数主要是初始化一些信号量,创建一个线程程序,调用这个线程程序。

static cmr_int camera_init_thread_proc(struct cmr_msg *message, void *p_data) {
    cmr_int ret = CMR_CAMERA_SUCCESS;
    cmr_u32 msg_type = 0;
    cmr_uint evt = 0;
    cmr_u32 camera_id = CAMERA_ID_MAX;
    struct camera_context *cxt = (struct camera_context *)p_data;

    msg_type = (cmr_u32)message->msg_type;

    switch (msg_type) {
    case CMR_EVT_INIT:
        cxt->err_code = camera_res_init_internal((cmr_handle)cxt);
        if (cxt->err_code) {
            camera_res_deinit_internal((cmr_handle)cxt);
        }
        CMR_LOGI("cb thread inited");
        break;
    ......
    default:
        break;
    }

    return ret;
}
static cmr_int camera_res_init_internal(cmr_handle oem_handle) {
    cmr_int ret = CMR_CAMERA_SUCCESS;

    struct camera_context *cxt = (struct camera_context *)oem_handle;

    ret = camera_ipm_init(oem_handle);
    //初始化oem_handle->ipm_cxt->ipm_handle

    ret = camera_setting_init(oem_handle);
    //初始化oem_handle->setting_cxt->setting_handle

    ret = camera_focus_init(oem_handle);
    //初始化oem_handle->focus_cxt->focus_handle

    ret = camera_jpeg_init(oem_handle);
    //初始化oem_handle->jpeg_cxt->jpeg_handle,这里导入libjpeg_hw_sprd.so

    ret = camera_scaler_init(oem_handle);
    //初始化oem_handle->scaler_cxt->scaler_handle,这里会open /dev/sprd_cpp

    ret = camera_rotation_init(oem_handle);
    //初始化oem_handle->rot_cxt->rotation_handle,这里会open /dev/sprd_cpp

    ret = camera_preview_init(oem_handle);

    ret = camera_interface_init();

    ret = camera_snapshot_init(oem_handle);

    ret = camera_init_thread(oem_handle);

    return ret;
}

这个接口这要是对camera_context 中成员变量xxx_context 进行初始化,初始化对应的工作程序。

这里主要看一下preview 和 snapshot 相关的初始化

1)camera_preview_init

这里是继续给oem_handle下的各种context初始化。

cmr_int camera_preview_init(cmr_handle oem_handle) {
    cmr_int ret = CMR_CAMERA_SUCCESS;
    struct camera_context *cxt = (struct camera_context *)oem_handle;
    struct preview_context *prev_cxt = NULL;
    struct preview_init_param init_param;

    prev_cxt = &cxt->prev_cxt;

    init_param.oem_handle = oem_handle;
    init_param.ipm_handle = cxt->ipm_cxt.ipm_handle;
    init_param.ops.channel_cfg = camera_channel_cfg;
    //...很多操作函数的赋值,省略
    init_param.oem_cb = camera_preview_cb;
    init_param.private_data = NULL;
    init_param.sensor_bits = (1 << cxt->camera_id);
    ret = cmr_preview_init(&init_param, &prev_cxt->preview_handle);

    prev_cxt->inited = 1;

    return ret;
}

在cmr_preview_init 中主要是将init_param 用来初始化preview_handle 的成员变量。同时也生成几个很重要的线程程序。

        cmr_thread_create(&handle->thread_cxt.assist_thread_handle,
                                PREV_MSG_QUEUE_SIZE, prev_assist_thread_proc,
                                (void *)handle);

        cmr_thread_create(&handle->thread_cxt.thread_handle,
                                PREV_MSG_QUEUE_SIZE, prev_thread_proc,
                                (void *)handle);

        cmr_thread_create(&handle->thread_cxt.cb_thread_handle,
                            PREV_MSG_QUEUE_SIZE, prev_cb_thread_proc,
                            (void *)handle);

这些程序在预览流程中有很重要的作用。

2)camera_snapshot_init

这个和cmr_preview_init 类似,但是生成的线程程序会多很多。

snapshot_context -----> snp_context---------> snp_thread_context 有多少个cmr_handle了

3)camera_init_thread

 是对camera_context 下的cmr_handle 生成线程程序。

3、camera_isp_init

isp这一类的还不太懂暂时这样。

总结:

我觉这个open 流程主要是对sensor、isp等进行简单初始化和设置,注册操作函数集和回调函数,同时生成一些线程程序,便于preview 和 snapshot 时调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值