下面我们来看下cmr_grab的重要内容
cmr_int cmr_grab_init(struct grab_init_param *init_param_ptr,cmr_handle *grab_handle)
p_grab->fd = open(CMR_GRAB_DEV_NAME, O_RDWR, 0);
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);
ret = pthread_mutex_init(&p_grab->path_mutex[channel_id], NULL);
ret = ioctl(p_grab->fd, SPRD_IMG_IO_GET_DCAM_RES, &res);
ret = cmr_grab_create_thread((cmr_handle)p_grab);
cmr_int cmr_grab_deinit(cmr_handle grab_handle)
ret = cmr_grab_kill_thread(grab_handle);
op.cmd = SPRD_IMG_STOP_DCAM;
op.sensor_id = p_grab->init_param.sensor_id;
cnt = write(p_grab->fd, &op, sizeof(struct sprd_img_write_op));
ret = ioctl(p_grab->fd, SPRD_IMG_IO_PUT_DCAM_RES, &res);
pthread_mutex_destroy(&p_grab->cb_mutex);
pthread_mutex_destroy(&p_grab->dcam_mutex);
pthread_mutex_destroy(&p_grab->status_mutex);
pthread_mutex_destroy(&p_grab->path_mutex[channel_id]);
老规矩,init 与 deinit 的操作基本是相对的,创建了什么就要销毁什么
SPRD_IMG_IO_GET_IOMMU_STATUS
SPRD_IMG_IO_SET_CAM_SECURITY
SPRD_IMG_IO_SET_CAP_ZSL_INFO
SPRD_ISP_IO_SET_PULSE_LINE
SPRD_ISP_IO_SET_VCM_LOG
SPRD_ISP_IO_SET_NEXT_VCM_POS
cmr_grab_evt_reg 是在拿到帧数据之后向上回调的,我们后面在接收帧数据的时候会在看到这个函数
void cmr_grab_evt_reg(cmr_handle grab_handle, cmr_evt_cb grab_event_cb) {
struct cmr_grab *p_grab;
p_grab = (struct cmr_grab *)grab_handle;
if (!p_grab)
return;
pthread_mutex_lock(&p_grab->cb_mutex);
p_grab->grab_evt_cb = grab_event_cb;
pthread_mutex_unlock(&p_grab->cb_mutex);
return;
}
cmr_int cmr_grab_if_cfg(cmr_handle grab_handle, struct sensor_if *sn_if)
cmr_int cmr_grab_sw_3dnr_cfg(cmr_handle grab_handle,struct sprd_img_3dnr_param *threednr_info)
cmr_int cmr_grab_sn_cfg(cmr_handle grab_handle, struct sn_cfg *config)
static cmr_int cmr_grab_cap_cfg_common(cmr_handle grab_handle,struct cap_cfg *config,cmr_u32 channel_id,struct img_data_end *endian)
cmr_int cmr_grab_cap_cfg(cmr_handle grab_handle, struct cap_cfg *config,cmr_u32 *channel_id, struct img_data_end *endian)
cmr_int cmr_grab_3dnr_cfg(cmr_handle grab_handle, cmr_u32 channel_id,cmr_u32 need_3dnr)
cmr_int cmr_grab_longexp_cfg(cmr_handle grab_handle, cmr_u32 need_longexp)
cmr_int cmr_grab_auto_3dnr_cfg(cmr_handle grab_handle,cmr_u32 auto_3dnr_enable)
cmr_int cmr_grab_cap_cfg_lightly(cmr_handle grab_handle, struct cap_cfg *config,cmr_u32 channel_id)
cmr_int cmr_grab_buff_cfg(cmr_handle grab_handle, struct buffer_cfg *buf_cfg)
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_ON, &stream_on); //start
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_OFF, &stream_on);//stop
他们分别在打开cameraApp 和 退出 CameraApp 的时候被调用的,从如下log时序中可以很清楚的看到。
Line 89953: 07-23 19:57:53.826 8634 8634 I CAM_CameraActivity Drea: onStartTasks start!
Line 92901: 07-23 19:57:55.832 531 8731 D cmr_grab: 1232, cmr_grab_cap_start: ret = 0
Line 102592: 07-23 19:57:59.978 8634 8634 I CAM_CameraActivity Drea: onPauseTasks start!
Line 103137: 07-23 19:58:00.146 531 8731 D cmr_grab: 1274, cmr_grab_cap_stop: ret = 0
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_PAUSE, &temp);//pause
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_RESUME, &temp);//resume
根据log,这两个函数是在开启拍照 和 需要的拍照帧数据都拿到后分别调用的
ret = ioctl(p_grab->fd, SPRD_IMG_IO_START_CAPTURE, &capture_param);
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STOP_CAPTURE, &stop);
注:cmr_grab_stop_capture 在退出camera的时候也会被调用一次
常规拍照流程暂未看到这两个函数的调用
cmr_grab_thread_proc 就是接受帧数据的函数
static void *cmr_grab_thread_proc(void *data)
CAMERA_IRQ_IMG //1
CAMERA_IRQ_FDRL //9
CAMERA_IRQ_FDRH //10
CAMERA_IRQ_4IN1_DONE //6
CAMERA_IRQ_STATIS //2
CAMERA_IRQ_DONE //3
其中预览和拍照的帧数据都是 CAMERA_IRQ_IMG ,log打印看到也有 2、3这两种类型,但是并没有走后续处理流程,我们目前只关注 CAMERA_IRQ_IMG 类型。
从参数 data中使用指令 SPRD_IMG_GET_FRM_BUFFER 读数据 到 op 对象中
struct cmr_grab *p_grab;
p_grab = (struct cmr_grab *)data;
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;
}
然后从op对象中可以拿到channel_id的值
op.parm.frame.channel_id
log中看到各类型的channel_id值
preview ---> 1
snapshot ---> 3
callback ---> 2
yuv2 ---> 5
struct frm_info frame;
frame.height = op.parm.frame.height;
frame.frame_id = op.parm.frame.index;
frame.frame_real_id = op.parm.frame.real_index;
frame.sec = op.parm.frame.sec;
frame.usec = op.parm.frame.usec;
frame.monoboottime = op.parm.frame.monoboottime;
frame.length = op.parm.frame.length;
frame.base = op.parm.frame.frm_base_id;
frame.fmt = cmr_grab_get_img_type(op.parm.frame.img_fmt);
frame.yaddr = op.parm.frame.yaddr;
frame.uaddr = op.parm.frame.uaddr;
frame.vaddr = op.parm.frame.vaddr;
frame.yaddr_vir = op.parm.frame.yaddr_vir;
frame.uaddr_vir = op.parm.frame.uaddr_vir;
frame.vaddr_vir = op.parm.frame.vaddr_vir;
frame.fd = op.parm.frame.mfd;
frame.frame_num = op.parm.frame.frame_id;
frame.zoom_ratio = op.parm.frame.zoom_ratio;
这里是指针函数 grab_evt_cb,我们在全面说过 cmr_grab_evt_reg 函数,就是给 grab_evt_cb 赋值的。
if (p_grab->grab_evt_cb) {
(*p_grab->grab_evt_cb)(
evt_id, &frame,
(void *)p_grab->init_param.oem_handle);
}
cmr_grab_evt_reg 是在 cmr_oem.c 中调用的,所以cmr_grab在拿到帧数据后会回调到 cmr_oem 中 的 camera_grab_evt_cb 函数。
后面就涉及到 预览帧 和 拍照帧的处理了,分别在 cmr_preview.c 和 cmr_snapshot.c 中,他们的内容都比较多,本篇的重点是cmr_grab.c , 我们会在分别单独写文章介绍cmr_preview.c 和 cmr_snapshot.c。
到这里 cmr_grab.c 就介绍得差不多了,大家只要记住,cmr_grab是oem端最开始拿到帧数据的地方,所以其它算法的流程都基于从这里拿到的帧数据之后。