当前位置:网站首页>Camera Hal OEM模块 ---- cmr_grab.c
Camera Hal OEM模块 ---- cmr_grab.c
2022-07-24 05:55:00 【Caroline_cheng】
cmr_grab.c是oem端拿到帧数据最底层的地方,直接操作节点
CMR_GRAB_DEV_NAME “/dev/sprd_image”
我们在hal端拿到的预览和拍照的数据都来自这个文件。这里是原始的数据,hal和oem在从cmr_grab中拿到数据后在跑各种算法。
cmr_grab还有大量的 ioctl 操作。
下面我们来看下cmr_grab的重要内容
1,cmr_grab_init
cmr_int cmr_grab_init(struct grab_init_param *init_param_ptr,cmr_handle *grab_handle)
1.1,open 节点
p_grab->fd = open(CMR_GRAB_DEV_NAME, O_RDWR, 0);
1.2,维护mutex
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);
1.3, SPRD_IMG_IO_GET_DCAM_RES
ret = ioctl(p_grab->fd, SPRD_IMG_IO_GET_DCAM_RES, &res);
1.4,创建thread
ret = cmr_grab_create_thread((cmr_handle)p_grab);
2,cmr_grab_deinit
cmr_int cmr_grab_deinit(cmr_handle grab_handle)
2.1 kill thread ,指令 SPRD_IMG_STOP_DCAM
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));
2.2 指令 SPRD_IMG_IO_PUT_DCAM_RES
ret = ioctl(p_grab->fd, SPRD_IMG_IO_PUT_DCAM_RES, &res);
2.3 mutex destory
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 的操作基本是相对的,创建了什么就要销毁什么
3,一些指令
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
4,帧数据回调
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;
}
5,一些 cfg
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)
6,cmr_grab_cap_start 和 cmr_grab_cap_stop
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
7,pause 和 resume
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_PAUSE, &temp);//pause
ret = ioctl(p_grab->fd, SPRD_IMG_IO_STREAM_RESUME, &temp);//resume
8,cmr_grab_start_capture 和 cmr_grab_stop_capture
根据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的时候也会被调用一次
9,cmr_grab_cap_resume 和 cmr_grab_cap_pause
常规拍照流程暂未看到这两个函数的调用
10,关键函数:cmr_grab_thread_proc
cmr_grab_thread_proc 就是接受帧数据的函数
static void *cmr_grab_thread_proc(void *data)
10.1 irq_type 含义
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 类型。
10.2 channel_id 的概念
从参数 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
10.3 封装帧数据的值
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;
10.4 回调
这里是指针函数 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端最开始拿到帧数据的地方,所以其它算法的流程都基于从这里拿到的帧数据之后。
边栏推荐
- 【LVGL(6)】显示中文设置,制作中文字库
- Sealos 打包部署 KubeSphere 容器平台
- Special effects - return to the top (kitten effects)
- 【学习笔记】url输入到页面展现中发生了什么?
- 【LVGL布局】柔性布局
- Detailed explanation of class loader and parental delegation mechanism
- 10分钟就能写出来的——25~30K的国外企业招聘面试考题,这不是轻轻松松吗~
- Machine learning case: smoking in pregnant women and fetal health
- Learn more about when to use MySQL two locks (table lock and row lock)
- Redis data type -string (string type)
猜你喜欢

【LVGL(5)】标签的(label)用法

Special effects - click the mouse, and a random color of love will appear

Machine learning case: smoking in pregnant women and fetal health

Kubernetes rapid installation

SparkSQL核心使用,220724,

Detailed analysis of the process (life cycle) of class loading

Directory and file management

Three level classification / menu query tree structure

《大厂面试》之JVM篇21问与答
![[small object velocimeter] only principle, no code](/img/df/b8a94d93d4088ebe8d306945fd9511.png)
[small object velocimeter] only principle, no code
随机推荐
Special effects - click the mouse, and a random color of love will appear
反射
(静态,动态,文件)三个版本的通讯录
这10种定时任务学会了,直接飘
随机森林、LGBM基于贝叶斯优化调参
Redis基本类型-哈希Hash
Breadth first search (template use)
三级分类/菜单的查询——树形结构
【LVGL(4)】对象的事件及事件冒泡
HashSet转数组
[lvgl] API functions for setting, changing and deleting styles of components
oss授权单个bucket权限
Redis.conf details
Redis入门
HashSet to array
You don't know these pits. You really don't dare to use BigDecimal
Machine learning case: smoking in pregnant women and fetal health
【LVGL】【阶段总结1】
[lvgl (1)] a brief introduction to lvgl
Geek planet ByteDance one stop data governance solution and platform architecture