目录
文章目录
- 1 log开的好,问题都能搞
- 2 lib
- 3 preview
- 3.1 打开视频流
- 3.1.1 cpp\_module\_start\_session
- 3.1.2 cpp\_thread\_create
- 3.1.3 cpp\_thread\_func
- sundp-3.1 cpp\_hardware\_open\_subdev(ctrl->cpphw)
- sundp-3.2 cpp\_hardware\_process\_command(ctrl->cpphw, cmd)
- 3.2 sensor视频流buffer队列
- 3.2.1 cpp\_thread\_func
- sundp-3.3 poll(pollfds, (nfds\_t)num\_fds, -1);
- sundp-3.4 cpp\_thread\_process\_pipe\_message
- sundp-3.5 cpp\_thread\_process\_hardware\_event
- sundp-3.6 cpp\_hardware\_process\_command
- sundp-3.7 msm\_cpp\_subdev\_do\_ioctl
- sundp-3.8 msm\_cpp\_subdev\_fops\_compat\_ioctl
- sundp-3.9 cpp\_module\_do\_ack
- sundp-3.10 MCT\_EVENT\_MODULE\_EVENT
- 4 dump image
- struct
- struct \_cpp\_module\_ctrl\_t
- struct \_cpp\_hardware\_t
- \_cpp\_thread\_msg\_t
- \_cpp\_hardware\_cmd\_t
- enum cpp\_hardware\_cmd\_type\_t
- struct \_cpp\_module\_session\_params\_t
1 log开的好,问题都能搞
- 22/12/01
在看preview流程的时候(mm-camera2/media-controller/modules/pproc-new/cpp/cpp_module.c ),上来有一句:
CPP_HIGH("name=%s", name);
查看定义在:mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_log.h
#define CPP_LOW(fmt, args…) CLOGL(CAM_CPP_MODULE, fmt, ##args)
#define CPP_HIGH(fmt, args…) CLOGH(CAM_CPP_MODULE, fmt, ##args)
#define CPP_ERR(fmt, args…) CLOGE(CAM_CPP_MODULE, fmt, ##args)
#define CPP_DBG(fmt, args…) CLOGD(CAM_CPP_MODULE, fmt, ##args)
#define CPP_INFO(fmt, args…) CLOGI(CAM_CPP_MODULE, fmt, ##args)
#define CPP_WARN(fmt, args…) CLOGW(CAM_CPP_MODULE, fmt, ##args)
看起来是针对mm-camera2/media-controller/modules/pproc-new/cpp/目录下的文件单独定义的log level。
CAM_CPP_MODULE是一个枚举值,同类型的还有以下这些。这些枚举值代表着不同模块的
typedef enum {CAM_NO_MODULE,CAM_MCT_MODULE,CAM_SENSOR_MODULE,CAM_IFACE_MODULE,CAM_ISP_MODULE,CAM_PPROC_MODULE,CAM_IMGLIB_MODULE,CAM_CPP_MODULE,CAM_HAL_MODULE,CAM_JPEG_MODULE,CAM_C2D_MODULE,CAM_STATS_MODULE,CAM_STATS_AF_MODULE,CAM_STATS_AEC_MODULE,CAM_STATS_AWB_MODULE,CAM_STATS_ASD_MODULE,CAM_STATS_AFD_MODULE,CAM_STATS_Q3A_MODULE,CAM_STATS_IS_MODULE,CAM_STATS_HAF_MODULE,CAM_STATS_CAF_SCAN_MODULE,CAM_SHIM_LAYER,CAM_LAST_MODULE
} cam_modules_t;
而像CLOGI,CLOGD,CLOGL等等也都有定义:
#undef CLOGI
#define CLOGI(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_INFO, fmt, ##args)
#undef CLOGD
#define CLOGD(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_DEBUG, fmt, ##args)
#undef CLOGL
#define CLOGL(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_LOW, fmt, ##args)
#undef CLOGW
#define CLOGW(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_WARN, fmt, ##args)
#undef CLOGH
#define CLOGH(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_HIGH, fmt, ##args)
#undef CLOGE
#define CLOGE(module, fmt, args...) \CLOGx(module, CAM_GLBL_DBG_ERR, fmt, ##args)
CLOGx的定义如下,如果g_cam_log数组的元素存在,就可以打印log。
/* logging macros */
#undef CLOGx
#define CLOGx(module, level, fmt, args...) \if (g_cam_log[module][level]) { \cam_debug_log(module, level, __func__, __LINE__, fmt, ##args); \}
g_cam_log是一个二维数组,代表当前跟踪日志记录配置。
/* current trace logging configuration */
/* g_cam_log[cam_modules_t][cam_global_debug_level_t] */
extern int g_cam_log[CAM_LAST_MODULE][CAM_GLBL_DBG_INFO + 1];
//CAM_LAST_MODULE和CAM_GLBL_DBG_INFO + 1代表两个enum的最大值
其中module代表的是组别,也就是上面的enum cam_modules_t。level代表的是log的等级,有如下等级:
/* values that persist.vendor.camera.global.debug can be set to */
/* all camera modules need to map their internal debug levels to this range */
typedef enum {CAM_GLBL_DBG_NONE = 0,CAM_GLBL_DBG_ERR = 1,CAM_GLBL_DBG_WARN = 2,CAM_GLBL_DBG_HIGH = 3,CAM_GLBL_DBG_DEBUG = 4,CAM_GLBL_DBG_LOW = 5,CAM_GLBL_DBG_INFO = 6
} cam_global_debug_level_t;
- 22/12/02
突然发现,HIGH等级的log貌似不打印,于是在文件里加上这几个debug的语句:
CPP_LOW(“sunmy_ low\n”);
CPP_HIGH(“sunmy_ HIGH\n”);
CPP_ERR(“sunmy_ ERR\n”);
CPP_DBG(“sunmy_ DBG\n”);
CPP_INFO(“sunmy_ INFO\n”);
CPP_WARN(“sunmy_ WARN\n”);
发现只有CPP_ERR,CPP_INFO,CPP_WARN等级的log默认打印,其余的默认不打印。
在camx-chi架构中,确实有很多log等级(比如verbose)需要setprop才能打开。这个的原理应该一样。
在文件mm-camera2/media-controller/modules/pproc-new/cpp/cpp_module.c 发现一个函数:
static void cpp_module_loglevel()
{char cpp_prop[PROPERTY_VALUE_MAX];memset(cpp_prop, 0, sizeof(cpp_prop));property_get("persist.vendor.camera.cpp.debug.mask", cpp_prop, "1");gcam_cpp_loglevel = atoi(cpp_prop);/* Keep the deafault modules enabled */property_get("persist.vendor.camera.cpp.mod.mask", cpp_prop, "2097407");g_cpp_log_featureMask = atoi(cpp_prop);
}
发现setprop persist.vendor.camera.cpp.debug.mask为不同的值就可以打印不同level的log。
这个结构体数组可以打印所有组别的log:
/* current trace logging configuration */
typedef struct {cam_global_debug_level_t level;int initialized;const char *name;const char *prop;
} module_debug_t;static module_debug_t cam_loginfo[(int)CAM_LAST_MODULE] = {{CAM_GLBL_DBG_ERR, 1,"", "persist.vendor.camera.global.debug" }, /* CAM_NO_MODULE */{CAM_GLBL_DBG_ERR, 1,"<MCT >", "persist.vendor.camera.mct.debug" }, /* CAM_MCT_MODULE */{CAM_GLBL_DBG_ERR, 1,"<SENSOR>", "persist.vendor.camera.sensor.debug" }, /* CAM_SENSOR_MODULE */{CAM_GLBL_DBG_WARN, 1,"<IFACE >", "persist.vendor.camera.iface.logs" }, /* CAM_IFACE_MODULE */{CAM_GLBL_DBG_ERR, 1,"<ISP >", "persist.vendor.camera.isp.debug" }, /* CAM_ISP_MODULE */{CAM_GLBL_DBG_ERR, 1,"<PPROC >", "persist.vendor.camera.pproc.debug.mask" }, /* CAM_PPROC_MODULE */{CAM_GLBL_DBG_WARN, 1,"<IMGLIB>", "persist.vendor.camera.imglib.logs" }, /* CAM_IMGLIB_MODULE */{CAM_GLBL_DBG_WARN, 1,"<CPP >", "persist.vendor.camera.cpp.debug.mask" }, /* CAM_CPP_MODULE */{CAM_GLBL_DBG_ERR, 1,"<HAL >", "persist.vendor.camera.hal.debug" }, /* CAM_HAL_MODULE */{CAM_GLBL_DBG_ERR, 1,"<JPEG >", "persist.vendor.camera.mmstill.logs" }, /* CAM_JPEG_MODULE */{CAM_GLBL_DBG_WARN, 1,"<C2D >", "persist.vendor.camera.c2d.debug.mask" }, /* CAM_C2D_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS >", "persist.vendor.camera.stats.debug" }, /* CAM_STATS_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_AF >", "persist.vendor.camera.stats.af.debug" }, /* CAM_STATS_AF_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_AEC >", "persist.vendor.camera.stats.aec.debug" }, /* CAM_STATS_AEC_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_AWB >", "persist.vendor.camera.stats.awb.debug" }, /* CAM_STATS_AWB_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_ASD >", "persist.vendor.camera.stats.asd.debug" }, /* CAM_STATS_ASD_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_AFD >", "persist.vendor.camera.stats.afd.debug" }, /* CAM_STATS_AFD_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_Q3A >", "persist.vendor.camera.stats.q3a.debug" }, /* CAM_STATS_Q3A_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_AIS >", "persist.vendor.camera.stats.is.debug" }, /* CAM_STATS_IS_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_HAF >", "persist.vendor.camera.stats.haf.debug" }, /* CAM_STATS_HAF_MODULE */{CAM_GLBL_DBG_ERR, 1,"<STATS_CAFSCAN >", "persist.vendor.camera.stats.cafscan" }, /* CAM_STATS_CAFSCAN_MODULE */{CAM_GLBL_DBG_ERR, 1,"<SHIM >", "persist.vendor.camera.shim.debug" }, /* CAM_SHIM_LAYER */
};
2 lib
frameworks/av/services/camera/libcameraservice/ /system/lib/libcameraservice.so
hardware/qcom/camera/QCamera2/ /vendor/lib/hw/camera.sdm660.so
hardware/qcom/camera/QCamera2/stack/mm-camera-interface/ /vendor/lib/libmmcamera_interface.so
hardware/interfaces/camera/device/1.0/ /system/lib/android.hardware.camera.device@1.0.so
hardware/interfaces/camera/device/3.2/default/ /vendor/lib/camera.device@3.2-impl.so
mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/ /vendor/lib/libmmcamera2_cpp_module.so
mm-camera/mm-camera2/media-controller/mct_shim_layer/ /vendor/lib/libmmcamera2_mct_shimlayer.so
mm-camera/mm-camera2/media-controller/mct/ /vendor/lib/libmmcamera2_mct.so
3 preview
framework preview
3.1 打开视频流
3.1.1 cpp_module_start_session
打开摄像头preview时,会调用到cpp_module_start_session方法: vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_module.c
boolean cpp_module_start_session(mct_module_t *module, uint32_t sessionid)
{cpp_module_ctrl_t *ctrl = (cpp_module_ctrl_t *) MCT_OBJECT_PRIVATE(module);if(ctrl->session_params[i] == NULL) {//初始化ctrl->session_params[]的内容//1.申请空间ctrl->session_params[i] = (cpp_module_session_params_t*) CAM_MALLOC(sizeof(cpp_module_session_params_t))//2.清零memset(ctrl->session_params[i], 0x00, sizeof(cpp_module_session_params_t));//3.初始化session_params 参考struct _cpp_module_session_params_t的成员}/* start the thread only when first session starts */if(ctrl->session_count == 0) {/* spawn the cpp thread */rc = cpp_thread_create(module);}
}
3.1.2 cpp_thread_create
将cpp_module_start_session的参数(mct_module_t *module)透传到cpp_thread_create中创建线程: vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_thread.c
int32_t cpp_thread_create(mct_module_t *module)
{...//设置cpp_thread_started的标志ctrl->cpp_thread_started = FALSE;//创建线程 cpp_thread_func 线程函数的入口地址rc = pthread_create(&(ctrl->cpp_thread), NULL, cpp_thread_func, module);//修改线程名pthread_setname_np(ctrl->cpp_thread, "CAM_cpp");/* wait to confirm if the thread is started */ //PTHREAD_COND_WAIT_TIME即pthread_cond_timedwait 当在指定时间内有信号传过来时,pthread_cond_timedwait()返回0,否则返回一个非0数,rc就是返回值PTHREAD_COND_WAIT_TIME(&(ctrl->th_start_cond), &(ctrl->cpp_mutex),&timeout, CPP_WAIT_TIMEOUT, rc);
}
3.1.3 cpp_thread_func
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_thread.c
void* cpp_thread_func(void* data)
{mct_module_t *module = (mct_module_t *) data;cpp_module_ctrl_t *ctrl = (cpp_module_ctrl_t *) MCT_OBJECT_PRIVATE(module);PTHREAD_MUTEX_LOCK(&(ctrl->cpp_mutex));//设置cpp_thread_started状态,代表cpp_thread已经跑起来了ctrl->cpp_thread_started = TRUE;//用于唤醒th_start_condpthread_cond_signal(&(ctrl->th_start_cond));//------------------sundp-3.1--------------/* open the cpp hardware */rc = cpp_hardware_open_subdev(ctrl->cpphw); /* subscribe for event on subdev fd *///注意cpp_hardware_cmd_t里的联合体cpp_hardware_cmd_t cmd;//cmd.type代表此命令的类型,除了这里的订阅事件,还有像CPP_HW_CMD_STREAMON,CPP_HW_CMD_STREAMON等等cmd.type = CPP_HW_CMD_SUBSCRIBE_EVENT; //------------------sundp-3.2--------------rc = cpp_hardware_process_command(ctrl->cpphw, cmd); /* poll on the pipe readfd and subdev fd */struct pollfd pollfds[2];uint32_t num_fds = 2;int ready = 0;uint32_t i = 0;pollfds[PIPE_FD_IDX].fd = ctrl->pfd[READ_FD];pollfds[PIPE_FD_IDX].events = POLLIN|POLLPRI;pollfds[SUBDEV_FD_IDX].fd = ctrl->cpphw->subdev_fd;pollfds[SUBDEV_FD_IDX].events = POLLIN|POLLPRI;while(1) {/* poll on the fds with no timeout *///------------------sundp-3.3--------------ready = poll(pollfds, (nfds_t)num_fds, -1); if(ready > 0) {/* loop through the fds to see if any event has occured */for(i=0; i<num_fds; i++) {if(pollfds[i].revents & (POLLIN|POLLPRI)) {//pollfds[0].revents = 1//pollfds[1].revents = 0//pollfds[0].revents = 0//pollfds[1].revents = 2switch(i) {case PIPE_FD_IDX: {int num_read=0;cpp_thread_msg_t pipe_msg;num_read = read(pollfds[i].fd, &(pipe_msg),sizeof(cpp_thread_msg_t));//------------------sundp-3.4--------------rc = cpp_thread_process_pipe_message(ctrl, pipe_msg); break;}case SUBDEV_FD_IDX: {//------------------sundp-3.5--------------rc = cpp_thread_process_hardware_event(ctrl); //读到dev fd消息,处理内核事件 break;}}}}}
}
sundp-3.1 cpp_hardware_open_subdev(ctrl->cpphw)
这里打开v4l的subdev。
ctrl->cpphw 是struct cpp_hardware_t定义的,结构体成员subdev_ids[MAX_CPP_DEVICES]代表的是:/dev/v4l-sundev*:
sdm660_64:/dev # ls v4l
v4l-subdev0 v4l-subdev11 v4l-subdev14 v4l-subdev17 v4l-subdev2 v4l-subdev22 v4l-subdev4 v4l-subdev7
v4l-subdev1 v4l-subdev12 v4l-subdev15 v4l-subdev18 v4l-subdev20 v4l-subdev23 v4l-subdev5 v4l-subdev8
v4l-subdev10 v4l-subdev13 v4l-subdev16 v4l-subdev19 v4l-subdev21 v4l-subdev3 v4l-subdev6 v4l-subdev9
这里前后置 打开的都是v4l-subdev17
代码路径:
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_hardware.c
int32_t cpp_hardware_open_subdev(cpp_hardware_t *cpphw)
{int fd;char dev_name[SUBDEV_NAME_SIZE_MAX];snprintf(dev_name, sizeof(dev_name), "/dev/v4l-subdev%d",cpphw->subdev_ids[0]);//打开v4l-subdevXX设备fd = open(dev_name, O_RDWR | O_NONBLOCK);cpphw->subdev_fd = fd;//flag已经打开设备cpphw->subdev_opened = TRUE;//通过ioctl,获取设备参数rc = ioctl(cpphw->subdev_fd, VIDIOC_MSM_CPP_GET_INST_INFO, &v4l2_ioctl);//填充ctrl->cpphw的信息:
}
open设备节点操作,对应到内核,kernel/msm-4.14/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
cpp_open_node 主要做了两件事:1、初始化mem, 2、初始化硬件
cpp_init_mem() : 其实就是获取cpp_dev->iommu_hdl,这个东西是在msm_cam_smmu设备driver中统一管理的,vfe中有记录过这里。
cpp_init_hardware():设置一些硬件参数、时钟、注册中断以及buf管理接口:msm_cam_buf_mgr_register_ops()
static int cpp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{cpp_dev = v4l2_get_subdevdata(sd);if (cpp_dev->cpp_open_cnt == 1) {rc = cpp_init_mem(cpp_dev);rc = cpp_init_hardware(cpp_dev);cpp_dev->state = CPP_STATE_IDLE;}
}
VIDIOC_MSM_CPP_GET_INST_INFO不重要,简单记录:
static long msm_cpp_subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{switch (cmd) {case VIDIOC_DQEVENT:return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);case VIDIOC_SUBSCRIBE_EVENT:return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);case VIDIOC_MSM_CPP_GET_INST_INFO: {uint32_t i;struct cpp_device *cpp_dev = v4l2_get_subdevdata(sd);struct msm_camera_v4l2_ioctl_t *ioctl_ptr = arg;struct msm_cpp_frame_info_t inst_info;memset(&inst_info, 0, sizeof(struct msm_cpp_frame_info_t));for (i = 0; i < MAX_ACTIVE_CPP_INSTANCE; i++) {if (cpp_dev->cpp_subscribe_list[i].vfh == vfh) {inst_info.inst_id = i;break;}}}break;default:return v4l2_subdev_call(sd, core, ioctl, cmd, arg);}
}
sundp-3.2 cpp_hardware_process_command(ctrl->cpphw, cmd)
cpp_hardware_process_command 用于处理给硬件的命令。在此过程中更新硬件状态。
代码路径:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_hardware.c
int32_t cpp_hardware_process_command(cpp_hardware_t *cpphw,cpp_hardware_cmd_t cmd)
{...switch (cmd.type) {case CPP_HW_CMD_GET_CAPABILITIES: rc = cpp_hardware_get_capabilities(cpphw); break;case CPP_HW_CMD_SUBSCRIBE_EVENT: rc = cpp_hardware_subcribe_v4l2_event(cpphw); break;case CPP_HW_CMD_UNSUBSCRIBE_EVENT: rc = cpp_hardware_unsubcribe_v4l2_event(cpphw);break;case CPP_HW_CMD_NOTIFY_EVENT: rc = cpp_hardware_notify_event_get_data(cpphw, cmd.u.event_data); break;case CPP_HW_CMD_STREAMON: rc = cpp_hardware_process_streamon(cpphw, cmd.u.buff_update);break;case CPP_HW_CMD_STREAMOFF: rc = cpp_hardware_process_streamoff(cpphw, cmd.u.streamoff_data); break;case CPP_HW_CMD_LOAD_FIRMWARE: rc = cpp_hardware_load_firmware(cpphw); break;case CPP_HW_CMD_PROCESS_FRAME: rc = cpp_hardware_process_frame(cpphw, &cmd); break;case CPP_HW_CMD_PROCESS_PARTIAL_FRAME:rc = cpp_hardware_process_partial_frame(cpphw, cmd.u.partial_frame); break;case CPP_HW_CMD_QUEUE_BUF: rc = cpp_hardware_send_buf_done(cpphw, cmd.u.event_data); break;case CPP_HW_CMD_SET_CLK: rc = cpp_hardware_set_clock(cpphw, &cmd.u.clock_settings); break;case CPP_HW_CMD_BUF_UPDATE: rc = cpp_hardware_update_buffer_list(cpphw, cmd.u.buff_update); break;case CPP_HW_CMD_POP_STREAM_BUFFER: rc = cpp_hardware_pop_stream_buffer(cpphw, cmd.u.event_data); break;case CPP_HW_CMD_NOTIFY_BUF_DONE: rc = cpp_hardware_notify_buf_done(cpphw, cmd.u.buf_done_identity); break;case CPP_HW_CMD_UPDATE_PENDING_BUF: rc = cpp_hardware_update_pending_buffer(cpphw, cmd.u.status); break;default: CPP_ERR("bad command type=%d", cmd.type); }...
}
这里的是CPP_HW_CMD_SUBSCRIBE_EVENT即cpp_hardware_subcribe_v4l2_event
订阅subdevfd上的事件,通知硬件打开preview.
v4l2_event_subscription定义在:kernel/msm-4.14/include/uapi/linux/videodev2.h
struct v4l2_event_subscription {
—__u32>–>—>—>—type;
—__u32>–>—>—>—id;
—__u32>–>—>—>—flags;
—__u32>–>—>—>—reserved[5];
};
V4L2_EVENT_CPP_FRAME_DONE的定义:
#define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0)
V4L2_EVENT_PRIVATE_START的定义:
#define V4L2_EVENT_PRIVATE_START>—>—0x08000000
static int32_t cpp_hardware_subcribe_v4l2_event(cpp_hardware_t *cpphw)
{struct v4l2_event_subscription sub;struct msm_camera_v4l2_ioctl_t v4l2_ioctl;sub.id = cpphw->inst_id;sub.type = V4L2_EVENT_CPP_FRAME_DONE;rc = ioctl(cpphw->subdev_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);cpphw->event_subs_info.valid = TRUE;cpphw->event_subs_info.id = sub.id;cpphw->event_subs_info.type = sub.type;return 0;
}
ioctl发送到内核: kernel/msm-4.14/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
static long msm_cpp_subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{//得到video devicestruct video_device *vdev = video_devdata(file);//得到v4l2_subdevstruct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev);struct v4l2_fh *vfh = file->private_data;switch (cmd) {...case VIDIOC_SUBSCRIBE_EVENT:return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);...}
}
v4l2_subdev_call(sd, core, subscribe_event, vfh, arg)是一个宏:
#define v4l2_subdev_call(sd, o, f, args...)> \({ \int __result; \if (!(sd)) \__result = -ENODEV;> \else if (!((sd)->ops->o && (sd)->ops->o->f)) \__result = -ENOIOCTLCMD; \else \__result = (sd)->ops->o->f((sd), ##args); \__result; \})
(sd)->ops->o->f((sd), ##args)对应的是函数指针:
int (*subscribe_event)(struct v4l2_subdev *sd, struct v4l2_fh *fh,struct v4l2_event_subscription *sub);
指向的函数是msm_cpp_subscribe_event。
static struct v4l2_subdev_core_ops msm_cpp_subdev_core_ops = {
—.ioctl = msm_cpp_subdev_ioctl,
—.subscribe_event = msm_cpp_subscribe_event,
—.unsubscribe_event = msm_cpp_unsubscribe_event,
};
static int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, struct v4l2_event_subscription *sub)
{return v4l2_event_subscribe(fh, sub, MAX_CPP_V4l2_EVENTS, NULL);
}
V4L2 events 提供一种将event传递到用户空间的通用方式。
v4l2_event_subscribe (fh, sub , elems, ops)
用来订阅事件,ops参数可以让驱动指定一个回调函数:add,del,replace,merge。一共有4个可选的回调函数,如果不需要也可以传入NULL参数。 kernel/msm-4.14/drivers/media/v4l2-core/v4l2-event.c
int v4l2_event_subscribe(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub, unsigned elems,const struct v4l2_subscribed_event_ops *ops)
{struct v4l2_subscribed_event *sev, *found_ev;sev = kvzalloc(sizeof(*sev) + sizeof(struct v4l2_kevent) * elems,GFP_KERNEL);for (i = 0; i < elems; i++) sev->events[i].sev = sev;sev->type = sub->type; sev->id = sub->id;sev->flags = sub->flags; sev->fh = fh;sev->ops = ops;found_ev = v4l2_event_subscribed(fh, sub->type, sub->id);if (!found_ev) list_add(&sev->list, &fh->subscribed);if (found_ev) {kvfree(sev);} else if (sev->ops && sev->ops->add) {ret = sev->ops->add(sev, elems);}
}
3.2 sensor视频流buffer队列
3.2.1 cpp_thread_func
上文在函数cpp_thread_func中说了sundp-3.1和sundp-3.2,接下来说一下剩下的:
....
/* poll on the pipe readfd and subdev fd */
struct pollfd pollfds[2];
uint32_t num_fds = 2;
int ready = 0;
uint32_t i = 0;
pollfds[PIPE_FD_IDX].fd = ctrl->pfd[READ_FD];
pollfds[PIPE_FD_IDX].events = POLLIN|POLLPRI;
//POLLIN 有数据可读。
//POLLPRI 有紧迫数据可读。
pollfds[SUBDEV_FD_IDX].fd = ctrl->cpphw->subdev_fd;
pollfds[SUBDEV_FD_IDX].events = POLLIN|POLLPRI;
CPP_HIGH("cpp_thread entering the polling loop...");
while(1) {ready = poll(pollfds, (nfds_t)num_fds, -1);
....
sundp-3.3 poll(pollfds, (nfds_t)num_fds, -1);
sundp-3.1和sundp-3.2启动v4l2设备成功后,cpp_thread线程同时侦听一个pipe fd,和设备节点/dev/v4l-subdevXX
( 注:打开v4l-subdevXX设备
fd = open(dev_name, O_RDWR | O_NONBLOCK);
cpphw->subdev_fd = fd;)。
struct pollfd pollfds[2];
struct pollfd{int fd; /*文件描述符,如建立socket后获取的fd, 此处表示想查询的文件描述符*/short events; /*等待的事件,就是要监测的感兴趣的事情*/short revents; /*实际发生了的事情*/
};
这里的ready = poll(pollfds, (nfds_t)num_fds, -1);是将当前的文件指针挂到等待队列中
结构介绍:
int poll(struct pollfd *fds, unsigned int nfds, int timeout)
参数介绍:
pollfd *fds : 指向pollfd结构体数组,用于存放需要检测器状态的Socket 描述符或其它文件描述符。
unsigned int nfds: 指定pollfd 结构体数组的个数,即监控几个pollfd.
timeout:指poll() 函数调用阻塞的时间,单位是ms.如果timeout=0则不阻塞,如timeout=INFTIM 表 示一直阻塞直到感兴趣的事情发生。
返回值:
0 表示数组fds 中准备好读,写或出错状态的那些socket描述符的总数量
==0 表示数组fds 中都没有准备好读写或出错,当poll 阻塞超时timeout 就会返回。
-1 表示poll() 函数调用失败,同时回自动设置全局变量errno.
函数特点:
每当函数调用后,不会清空这个fds指向的数组,适用于大量socket 描述符的情况。而select()函数调用后会清空它所检测的socket描述符集合,因此select()只是用检测一个socket 描述符的情况。
如果待监测的socket 描述符为负值,则这个描述符的检测就会被忽略,poll()函数返回时直接把revents 设置为0
该poll()函数不会受到socket 描述符上的O_NDELAY 标记和O_NONBLOCK 标记的影响。
sundp-3.4 cpp_thread_process_pipe_message
poll函数运行成功后,接下来会循环浏览num_fds(即pipe fd和subdev_fd)
以查看是否发生了任何事件,当pipe fd上有消息时,先读到pipe_msg。
case PIPE_FD_IDX: {int num_read=0;cpp_thread_msg_t pipe_msg;num_read = read(pollfds[i].fd, &(pipe_msg),sizeof(cpp_thread_msg_t));rc = cpp_thread_process_pipe_message(ctrl, pipe_msg); break;}
接下来进入cpp_thread_process_pipe_message处理。 vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_thread.c
static int32_t cpp_thread_process_pipe_message(cpp_module_ctrl_t *ctrl,cpp_thread_msg_t msg)
{cpp_hardware_cmd_t cmd;switch(msg.type) {//这里应该是出错才会走。信息中止case CPP_THREAD_MSG_ABORT: ......//有事件case CPP_THREAD_MSG_NEW_EVENT_IN_Q: {cpp_module_event_t* cpp_event;/*当队列进程中有一些有效事件时,处理它 */while(1) {cpp_event = cpp_thread_get_event_from_queue(ctrl);if(!cpp_event) { break; }rc = cpp_thread_process_queue_event(ctrl, cpp_event);}break;}
}
cpp_thread_process_queue_event
cpp_event->type的类型:
typedef enum {
CPP_MODULE_EVENT_PROCESS_BUF,
CPP_MODULE_EVENT_DIVERT_BUF,
CPP_MODULE_EVENT_CLOCK,
CPP_MODULE_EVENT_PARTIAL_FRAME,
CPP_MODULE_EVENT_ISP_BUFFER_DROP
} cpp_module_event_type_t;
static int32_t cpp_thread_process_queue_event(cpp_module_ctrl_t *ctrl, cpp_module_event_t* cpp_event)
{//选择事件类型:预览的时候是CPP_MODULE_EVENT_PROCESS_BUFswitch(cpp_event->type) {case CPP_MODULE_EVENT_DIVERT_BUF:rc = cpp_thread_handle_divert_buf_event(ctrl, cpp_event);break;case CPP_MODULE_EVENT_PROCESS_BUF:rc = cpp_thread_handle_process_buf_event(ctrl, cpp_event);break;case CPP_MODULE_EVENT_CLOCK:rc = cpp_thread_handle_clock_event(ctrl, cpp_event);break;case CPP_MODULE_EVENT_PARTIAL_FRAME:rc = cpp_thread_handle_partial_frame_event(ctrl, cpp_event);break;case CPP_MODULE_EVENT_ISP_BUFFER_DROP:cpp_thread_handle_isp_drop_buffer_event(ctrl, cpp_event);break;
}
cpp_thread_handle_process_buf_event
static int32_t cpp_thread_handle_process_buf_event(cpp_module_ctrl_t* ctrl, cpp_module_event_t* cpp_event)
{cpp_module_stream_params_t *stream_params = NULL;cpp_module_session_params_t *session_params = NULL;......//填充cookie/*cookie用于将数据附加到内核帧,处理完成后将立即取回???*/cpp_module_hw_cookie_t *cookie = NULL;//用cpp_envent填充hw_params的参数cpp_hardware_params_t* hw_params = NULL;hw_params = &(cpp_event->u.process_buf_data.hw_params);hw_params->cookie = cookie;hw_params->frame_id = cpp_event->u.process_buf_data.isp_buf_divert.buffer.sequence; hw_params->timestamp = cpp_event->u.process_buf_data.isp_buf_divert.buffer.timestamp;hw_params->buffer_info.fd = in_frame_fd;....../* get stream parameters based on the event identity */cpp_module_get_params_for_identity(ctrl, hw_params->identity,&session_params, &stream_params);/*Before validation, swap dimensions if 90 or 270 degrees rotation*///画面的旋转角度交换?cpp_hardware_rotation_swap(hw_params,video_type_flag);/* before giving the frame to hw, make sure the parameters are good *///应该是验证当前帧的参数是否正确,不正确就丢弃if(FALSE == cpp_hardware_validate_params(hw_params)){......}//计算裁剪?rc = cpp_params_calculate_crop(hw_params);......cmd.type = CPP_HW_CMD_PROCESS_FRAME;cmd.ctrl = ctrl;cmd.u.hw_params = hw_params;//这里可以dump,可以看一下 第五章 dump
#ifdef _ANDROID_if (session_params->cpp_debug_enable)cpp_thread_dump_frame(hw_params,hw_params->buffer_info.fd,&cmd,1);
#endifrc = cpp_hardware_process_command(ctrl->cpphw, cmd); ....../* Update and post the current session's diag parameters *///更新并发布当前session的诊断参数cpp_module_util_update_session_diag_params(ctrl->p_module, hw_params);
}
cpp_hardware_process_command
执行到CPP_HW_CMD_PROCESS_FRAME,就是cpp_hardware_process_frame(): vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_hardware.c
static int32_t cpp_hardware_process_frame(cpp_hardware_t *cpphw, cpp_hardware_cmd_t *cmd)
{struct cpp_frame_info_t cpp_frame_infostruct msm_cpp_frame_info_t *msm_cpp_frame_info;......rc = cpp_params_create_frame_info(cpphw, hw_params, &cpp_frame_info);//将sysetm接口参数转换为msm frame cfg参数cpp_frame_info.frame_id = hw_params->frame_id;cpp_frame_info.timestamp = hw_params->timestamp;cpp_frame_info.identity = hw_params->identity;.......msm_cpp_frame_info = cpp_hardware_create_hw_frame(cpphw, &cpp_frame_info);/* send kernel ioctl for processing */struct msm_camera_v4l2_ioctl_t v4l2_ioctl;v4l2_ioctl.ioctl_ptr = (void *)msm_cpp_frame_info;v4l2_ioctl.len = sizeof(struct msm_cpp_frame_info_t);rc = ioctl(cpphw->subdev_fd, VIDIOC_MSM_CPP_CFG, &v4l2_ioctl);.......
}
VIDIOC_MSM_CPP_CFG通过ioctl,到了内核: kernel/msm-4.14/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c //内核的这部分我没看
static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{bool is_copytouser_req = truestruct msm_camera_v4l2_ioctl_t kp_ioctlvoid __user *up = (void __user *)arg;copy_from_user(&up32_ioctl, (void __user *)up, sizeof(up32_ioctl));kp_ioctl.id = up32_ioctl.id;kp_ioctl.len = up32_ioctl.len;kp_ioctl.trans_code = up32_ioctl.trans_code;kp_ioctl.ioctl_ptr = compat_ptr(up32_ioctl.ioctl_ptr);switch (cmd) {case VIDIOC_MSM_CPP_CFG32:{ copy_from_user(&k32_frame_info, (void __user *)kp_ioctl.ioctl_ptr, sizeof(k32_frame_info));cpp_frame = get_64bit_cpp_frame_from_compat(&kp_ioctl);/* Configure the cpp frame */if (cpp_frame) {rc = msm_cpp_cfg_frame(cpp_dev, cpp_frame);/* Cpp_frame can be free'd by cfg_frame in error */if (rc >= 0) {k32_frame_info.output_buffer_info[0] = cpp_frame->output_buffer_info[0];k32_frame_info.output_buffer_info[1] = cpp_frame->output_buffer_info[1];}}kp_ioctl.trans_code = rc;copy_to_user((void __user *)kp_ioctl.ioctl_ptr, &k32_frame_info, sizeof(k32_frame_info));cmd = VIDIOC_MSM_CPP_CFG;break;}。。。。。。
}
msm_cpp_cfg_frame
static int msm_cpp_cfg_frame(struct cpp_device *cpp_dev, struct msm_cpp_frame_info_t *new_frame)
{in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev,&new_frame->input_buffer_info,((new_frame->input_buffer_info.identity >> 16) & 0xFFFF),(new_frame->input_buffer_info.identity & 0xFFFF), &in_fd);op_index = new_frame->output_buffer_info[0].index;dup_index = new_frame->duplicate_buffer_info.index;if (new_frame->we_disable == 0) {int32_t iden = new_frame->identity;。。。。。。out_phyaddr0 = msm_cpp_fetch_buffer_info(cpp_dev, &new_frame->output_buffer_info[0],((iden >> 16) & 0xFFFF), (iden & 0xFFFF), &new_frame->output_buffer_info[0].fd);}out_phyaddr1 = out_phyaddr0;if (new_frame->duplicate_output) { 。。。。。。} //这个分支不执行。。。。。。msm_cpp_update_frame_msg_phy_address(cpp_dev, new_frame,in_phyaddr, out_phyaddr0, out_phyaddr1, tnr_scratch_buffer0, tnr_scratch_buffer1);rc = msm_cpp_set_group_buffer(cpp_dev, new_frame, out_phyaddr0, num_output_bufs);frame_qcmd->command = new_frame;rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd); // 将new_frame参数发送到硬件
}
msm_cpp_send_frame_to_hardware()最终会执行对硬件地址的写操作,将frame的参数写入硬件。(TODO)
sundp-3.5 cpp_thread_process_hardware_event
sundp-3.1和sundp-3.2启动v4l2设备成功后,cpp_thread线程侦听设备节点/dev/v4l-subdevXX的节点(sundp-3.3)。当有视频buffer准备好时,会向该节点写入数据,这样sundp-3.3返回。
继续前面代码的sundp-3.4
接下来就是 sundp-3.5
poll函数运行成功后,接下来会循环浏览num_fds(即pipe fd和subdev_fd)以查看是否发生了任何事件,当subdev_fd上有消息时,进入 vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_thread.c
static int32_t cpp_thread_process_hardware_event(cpp_module_ctrl_t *ctrl)
{......./* get the event data from hardware *///从硬件获取event数据cmd.type = CPP_HW_CMD_NOTIFY_EVENT;cmd.u.event_data = &event_data;rc = cpp_hardware_process_command(ctrl->cpphw, cmd); //sundp-3.6/* get stream parameters based on the event identity *///基于事件标识获取流参数 cpp_module_get_params_for_identity(ctrl, event_data.identity, &session_params, &stream_params);/* update the pending ack for this buffer */cookie = (cpp_module_hw_cookie_t *)event_data.cookie;buffer_access = event_data.input_buffer_access;rc = cpp_module_do_ack(ctrl, cookie->key, buffer_access); // 发送buf event sundp-3.9.......
}
sundp-3.6 cpp_hardware_process_command
首先从/dev/v4l-subdevXX节点读取event内容:
int32_t cpp_hardware_process_command(cpp_hardware_t *cpphw, cpp_hardware_cmd_t cmd)
{.......switch (cmd.type) {......case CPP_HW_CMD_NOTIFY_EVENT:rc = cpp_hardware_notify_event_get_data(cpphw, cmd.u.event_data);break;......}
}
cpp_hardware_notify_event_get_data
static int32_t cpp_hardware_notify_event_get_data(cpp_hardware_t *cpphw,cpp_hardware_event_data_t *event_data)
{struct v4l2_event event;//--------------------sundp-3.7----------rc = ioctl(cpphw->subdev_fd, VIDIOC_DQEVENT, &event); v4l2_ioctl.ioctl_ptr = (void *)&frame;v4l2_ioctl.len = sizeof(struct msm_cpp_frame_info_t);//--------------------sundp-3.8----------rc = ioctl(cpphw->subdev_fd, VIDIOC_MSM_CPP_GET_EVENTPAYLOAD, &v4l2_ioctl); event_data->frame_id = frame.frame_id;event_data->buf_idx = frame.input_buffer_info.index;event_data->out_fd = frame.output_buffer_info[0].fd;event_data->identity = frame.identity;......// 设置event_data的内容
}
首先是sundp-3.7,通过对节点/dev/v4l-subdevXX的ioctl,到了内核: kernel/msm-4.14/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
sundp-3.7 msm_cpp_subdev_do_ioctl
static long msm_cpp_subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{vdev = video_devdata(file);sd = vdev_to_v4l2_subdev(vdev);vfh = file->private_data;switch (cmd) {case VIDIOC_DQEVENT:return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);......
}
v4l2_event_dequeue就是从v4l设备的avaliable链表中取出第一个event,通过copy_to_user,返回给camera hal。
sundp-3.8 msm_cpp_subdev_fops_compat_ioctl
然后是sundp-3.8,通过对节点/dev/v4l-subdevXX的ioctl,到了内核: kernel/msm-4.14/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
static long msm_cpp_subdev_fops_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{bool is_copytouser_req = truestruct msm_camera_v4l2_ioctl_t kp_ioctlvoid __user *up = (void __user *)arg;copy_from_user(&up32_ioctl, (void __user *)up, sizeof(up32_ioctl));kp_ioctl.id = up32_ioctl.id;kp_ioctl.len = up32_ioctl.len;kp_ioctl.trans_code = up32_ioctl.trans_code;kp_ioctl.ioctl_ptr = compat_ptr(up32_ioctl.ioctl_ptr);switch (cmd) {.......case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD32:{struct msm_device_queue *queue = &cpp_dev->eventData_q;event_qcmd = msm_dequeue(queue, list_eventdata, POP_FRONT);get_compat_frame_from_64bit(process_frame, &k32_process_frame);copy_to_user((void __user *)kp_ioctl.ioctl_ptr, &k32_process_frame, sizeof(struct msm_cpp_frame_info32_t)));cmd = VIDIOC_MSM_CPP_GET_EVENTPAYLOAD;break;}......}if (is_copytouser_req) { // == true //转换为32位(compat),再copy to userup32_ioctl.id = kp_ioctl.id;up32_ioctl.len = kp_ioctl.len;up32_ioctl.trans_code = kp_ioctl.trans_code;up32_ioctl.ioctl_ptr = ptr_to_compat(kp_ioctl.ioctl_ptr);copy_to_user((void __user *)up, &up32_ioctl, sizeof(up32_ioctl));}
}
这里,将一个视频帧(frame)参数通过ioctl,返回给camera hal。
hal拿到帧参数后,将帧参数也填充到event_data中。最后,sundp-3.6返回,参数返回到event_data中。
接下来到了sundp-3.9
sundp-3.9 cpp_module_do_ack
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/pproc-new/cpp/cpp_module.c
int32_t cpp_module_do_ack(cpp_module_ctrl_t *ctrl, cpp_module_ack_key_t key, uint32_t buffer_access)
{......cpp_ack = cpp_module_find_ack_from_list(ctrl, key);cpp_ack->ref_count--;if(cpp_ack->ref_count == 0) {......cpp_module_send_buf_divert_ack(ctrl, cpp_ack->isp_buf_divert_ack);}
}static int32_t cpp_module_send_buf_divert_ack(cpp_module_ctrl_t *ctrl, isp_buf_divert_ack_t isp_ack)
{//创建eventmct_event_t event; // sundp-3.10event.type = MCT_EVENT_MODULE_EVENT;event.direction = MCT_EVENT_UPSTREAM;event.identity = isp_ack.identity;//sundp-3.11event.u.module_event.type = MCT_EVENT_MODULE_BUF_DIVERT_ACK;event.u.module_event.module_event_data = &isp_ack;rc = cpp_module_send_event_upstream(ctrl->p_module, &event);return 0;
}
sundp-3.10 MCT_EVENT_MODULE_EVENT
接下来到了这儿:
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/iface2/port_iface.c
static boolean port_iface_event_func(mct_port_t *mct_port, mct_event_t *event)
{switch (event->type) {case MCT_EVENT_CONTROL_CMD:/* MCT ctrl event */rc = port_iface_proc_mct_ctrl_cmd(mct_port, event);break;case MCT_EVENT_MODULE_EVENT: //对应了前面的event.type/* Event among modules */rc = port_iface_proc_module_event(mct_port, event);break;return rc;
}
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/iface2/iface_util.c
int iface_util_divert_ack(iface_t *iface, iface_session_t *session,uint32_t user_stream_id, uint32_t buf_idx, uint32_t is_dirty, boolean bayerdata, uint32_t buffer_access)
{if (hw_stream->isp_split_output_info.is_split == TRUE && hw_stream->stream_info.cam_stream_type != CAM_STREAM_TYPE_OFFLINE_PROC) {/*if hw stream split, only enqueue once since its shared buf*/rc = iface_axi_divert_ack( iface->isp_axi_data.axi_data[VFE0].axi_hw_ops->ctrl,&axi_divert_ack, sizeof(axi_divert_ack));......
}
vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/iface2/axi/iface_axi.c:
static boolean port_iface_proc_module_event(mct_port_t *mct_iface_port, mct_event_t *event)
{switch (mod_event->type) {//对应了前面的event.u.module_event.typecase MCT_EVENT_MODULE_BUF_DIVERT_ACK: { isp_buf_divert_ack_t *buf_divert_ack = (isp_buf_divert_ack_t*) mod_event->module_event_data;ret = iface_util_divert_ack(iface, session, UNPACK_STREAM_ID(event->identity),buf_divert_ack->buf_idx, buf_divert_ack->is_buf_dirty,buf_divert_ack->bayerdata, buf_divert_ack->buffer_access);}break;
}
这里,iface_quque_buf,将视频buf加入队列,送去显示。
int iface_axi_divert_ack( iface_axi_hw_t *axi_hw, iface_axi_buf_divert_ack_t *ack, uint32_t data_size __unused)
{stream = iface_axi_util_find_stream(axi_hw, ack->session_id, ack->stream_id);buf_handle = iface_find_matched_bufq_handle(axi_hw->buf_mgr,stream->hw_stream_info.session_id, ack->stream_id);rc = iface_queue_buf(axi_hw->buf_mgr,buf_handle, ack->buf_idx, ack->is_buf_dirty, axi_hw->fd,ack->buffer_access);
}
4 dump image
这里说一下怎么dump图像:
static int32_t cpp_thread_handle_process_buf_event(cpp_module_ctrl_t* ctrl,cpp_module_event_t* cpp_event)
{......
#ifdef _ANDROID_if (session_params->cpp_debug_enable)//1 表示dump输入,有另外的函数dump输出cpp_thread_dump_frame(hw_params,hw_params->buffer_info.fd,&cmd,1);
#endif.......
}
可见有两个条件:
1.#ifdef ANDROID
2.session_params->cpp_debug_enable为ture
第一个条件好说,第二个赋值为ture的地方是:
property_get("persist.vendor.camera.pproc.debug.en", value, "0");
enabled = atoi(value);
if (enabled)ctrl->session_params[i]->cpp_debug_enable = TRUE;
所以需要setprop persist.vendor.camera.pproc.debug.en 1
cpp_thread_dump_frame函数实现:
参数:
cpp_hardware_params_t hw_params:
int fd:
void *user:
bool ip_op:1 dump Input ; 0 dump Output
int cpp_thread_dump_frame(cpp_hardware_params_t *hw_params, int fd,void *user,bool ip_op)
{......//1.检查是否开启dump//这里也需要设置一下property_get("persist.vendor.camera.pproc.framedump", value, "0");enabled = atoi(value);if (!enabled) { CPPFrameCnt = 0; return 0; }//2.设置需要dump的frame数,默认20property_get("persist.vendor.camera.pproc.dump_cnt", value, "20");count = atoi(value);//3.dump输入or输出if(ip_op) { /* Input */cookie = (cpp_module_hw_cookie_t *)hw_params->cookie;memcpy(&dim_info,&hw_params->input_info,sizeof(cpp_params_dim_info_t));strlcpy(io,"Input",sizeof(io));} else { /* Output */cookie = cmd->u.event_data->cookie;memcpy(&dim_info,&hw_params->output_info,sizeof(cpp_params_dim_info_t));strlcpy(io,"Output",sizeof(io));hw_params->frame_id = cmd->u.event_data->frame_id;}//根据stream_type组包(即dump 图像的的文件名)switch(hw_params->stream_type) {//以preview举例:case CAM_STREAM_TYPE_PREVIEW: {snprintf(name, sizeof(name), QCAMERA_DUMP_FRM_LOCATION"%s_CPP_%s_Preview_%dx%d_%d.yuv",timeBuf,io,width[0],height[0],hw_params->frame_id);break;}.......}//openfile_fd = open(name, O_RDWR | O_CREAT, 0777);//writewritten_len += write(file_fd, data, (size_t)(dim_info.plane_info[i].plane_len));......
}
struct
struct _cpp_module_ctrl_t
struct _cpp_module_ctrl_t {mct_module_t *p_module;mct_module_t *parent_module;mct_queue_t *realtime_queue;mct_queue_t *partial_frame_queue;mct_queue_t *offline_queue;cpp_module_ack_list_t ack_list;pthread_t cpp_thread;pthread_cond_t th_start_cond;boolean cpp_thread_started;pthread_mutex_t cpp_mutex;int pfd[2];int32_t session_count;cpp_hardware_t *cpphw;cpp_module_clk_rate_list_t clk_rate_list;unsigned long clk_rate;boolean runtime_clk_update;pp_native_buf_mgr_t pp_buf_mgr;pp_native_buf_mgr_t pp_tnr_buf_mgr;cpp_module_session_params_t *session_params[CPP_MODULE_MAX_SESSIONS];cpp_submodule_func_tbl_t tnr_module_func_tbl;cpp_submodule_func_tbl_t pbf_module_func_tbl;mct_port_t *port_map[CPP_MODULE_MAX_SESSIONS][CPP_MODULE_MAX_STREAMS][2];/* last updated clock and bandwidth */int64_t clk;int64_t bw;/* current state for a clock update */cpp_clock_state clk_state;/* threshold count to trigger a clock bump down */int32_t clock_threshold;int32_t clock_dcvs;int32_t turbo_caps;volatile bool is_hw_error;uint32_t rtb_status;uint32_t sat_status;uint32_t soc_id;
};
struct _cpp_hardware_t
struct _cpp_hardware_t {uint32_t subdev_ids[MAX_CPP_DEVICES];int num_subdev;int subdev_fd;boolean subdev_opened;uint32_t inst_id;cpp_hardware_caps_t caps;cpp_hardware_info_t hwinfo;cpp_hardware_status_t status;cpp_firmware_version_t fw_version;cpp_hardware_event_subscribe_info_t event_subs_info;cpp_hardware_stream_status_t stream_status[CPP_HARDWARE_MAX_STREAMS];pthread_cond_t subdev_cond;pthread_mutex_t mutex;int num_iommu_cnt;int max_pending_buffer;uint32_t dump_preview_cnt;uint32_t dump_video_cnt;uint32_t dump_snapshot_cnt;int32_t max_supported_padding;void *private_data;uint32_t preview_frame_counter;uint32_t video_frame_counter;uint32_t offline_frame_counter;uint32_t snapshot_frame_counter;uint32_t postview_frame_counter;uint32_t analysis_frame_counter;
} ;
_cpp_thread_msg_t
typedef enum {CPP_THREAD_MSG_NEW_EVENT_IN_Q,CPP_THREAD_MSG_ABORT
} cpp_thread_msg_type_t;typedef struct _cpp_thread_msg_t {cpp_thread_msg_type_t type;void *data;
} cpp_thread_msg_t;
_cpp_hardware_cmd_t
typedef struct _cpp_hardware_cmd_t {cpp_hardware_cmd_type_t type;void *ctrl;void *return_payload;/* CPP_HW_CMD_PROCESS_FRAME - Partial frame, after the first payload is sent,the remainder is saved here and then split into more partial_framesin the thread */union {cpp_hardware_streamoff_event_t streamoff_data;cpp_hardware_event_data_t *event_data;cpp_hardware_params_t *hw_params;cpp_hardware_buff_update_t *buff_update;struct msm_cpp_frame_info_t *partial_frame;cpp_hardware_clock_settings_t clock_settings;uint32_t buf_done_identity;uint32_t status;} u;
} cpp_hardware_cmd_t;
enum cpp_hardware_cmd_type_t
typedef enum {CPP_HW_CMD_GET_CAPABILITIES,CPP_HW_CMD_SUBSCRIBE_EVENT,CPP_HW_CMD_UNSUBSCRIBE_EVENT,CPP_HW_CMD_NOTIFY_EVENT,CPP_HW_CMD_STREAMON,CPP_HW_CMD_STREAMOFF,CPP_HW_CMD_LOAD_FIRMWARE,CPP_HW_CMD_PROCESS_FRAME,CPP_HW_CMD_QUEUE_BUF,CPP_HW_CMD_GET_CUR_DIAG,CPP_HW_CMD_SET_CLK,CPP_HW_CMD_POP_STREAM_BUFFER,CPP_HW_CMD_BUF_UPDATE,CPP_HW_CMD_PROCESS_PARTIAL_FRAME,CPP_HW_CMD_NOTIFY_BUF_DONE,CPP_HW_CMD_UPDATE_PENDING_BUF,
} cpp_hardware_cmd_type_t;
struct _cpp_module_session_params_t
/* session specific parameters */
typedef struct _cpp_module_session_params_t {cpp_module_stream_params_t *stream_params[CPP_MODULE_MAX_STREAMS];int32_t stream_count;cpp_hardware_params_t hw_params;uint32_t session_id;cam_hfr_mode_t hfr_mode;cpp_params_aec_trigger_info_t aec_trigger;/* DIS enable flag to be used for frame hold */int32_t dis_enable;/* Latest frame id received from DIS crop event */cpp_module_dis_hold_t dis_hold;/* Hold frame until DIS crop is received for this frame */cpp_module_frame_hold_t frame_hold;ez_pp_params_t diag_params;cam_hal_version_t hal_version;cpp_per_frame_params_t per_frame_params;boolean is_stream_on;uint32_t stream_on_count;cam_fps_range_t fps_range;cam_stream_ID_t valid_stream_ids[FRAME_CTRL_SIZE];cam_stream_ID_t verify_proc_stream_ids[FRAME_CTRL_SIZE];pthread_mutex_t dis_mutex;modulesChromatix_t module_chromatix;chromatix_cpp_stripped_type *def_chromatix_stripped;boolean runtime_clk_update;cam_dimension_t camif_dim;uint32_t turbo_frame_count;int32_t clk_ref_threshold_idx;/* for Dual Cam: Primary or Secondary */bool is_slave;/* for Dual Cam: Main or Aux */cam_sync_type_t cam_type;int32_t link_session_id;int32_t native_buf_ref;cam_dual_camera_perf_control_t dualcam_perf;cpp_module_session_set_parm sticky_set_parm;cam_dual_camera_role_t cam_role;bool force_slave_process;boolean cpp_debug_enable;
} cpp_module_session_params_t;