Android Camera架构浅析 && Qualcomm 8X camera daemon进程浅析
2016-06-30 19:14
851 查看
转自:http://www.cokco.cn/thread-7779-1-1.html
Camera先看一下抽象层的主要流程:首先启动一个守护进程Main()(camdaemon.c)int qcamsvr_start(void)( qcamsvr.c){1. server_fd = open(server_dev_name, O_RDWR);//打开服务对应的文件节点2. if (mctl_load_comps()) //加载所有需要的组件3. rc = qcamsvr_load_gesture_lib(&gesture_info.gesture_lib);//加载手势库4. ez_server_socket_id = eztune_setup_server("127.0.0.1", "55555");if (pipe(ez_cmd_pipe)ez_prev_server_socket_id = eztune_setup_server("127.0.0.1", "55556");if(pipe(ez_prev_cmd_pipe)//创建两个socket端口,同时建立两个pipe文件对两个端口进行监控5. if (get_mctl_node_info(server_fd, &mctl_node_info))//通过服务节点获取服务的相关信息{//此处获取的是内核中调用msm_sensor_register()注册的sensor节点信息}6. sub.type = V4L2_EVENT_ALL;rc = ioctl(server_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);//通过服务设备文件的ioctl接口,订阅所有的事件7. config_arg.server_fd = server_fd; config_arg.ez_read_fd = ez_cmd_pipe[0]; config_arg.ez_write_fd = ez_cmd_pipe[1]; config_arg.ez_prev_read_fd = ez_prev_cmd_pipe[0]; config_arg.ez_prev_write_fd = ez_prev_cmd_pipe[1];//初始化配置线程的参数8.下面就是一个循环,对这几个文件进行poll do { fds[0].fd = server_fd; fds[0].events = POLLPRI; fds[1].fd = ez_server_socket_id; fds[1].events = POLLIN; fds[2].fd = ez_prev_server_socket_id; fds[2].events = POLLIN; rc = poll(fds, 3, timeoutms);if (fds[0].revents & POLLPRI) { /* Server Node Wake Up * //对服务的设备文件进行监视,当遇到打开事件的时候,立即创建一个配置线程 rc = qcamsvr_process_server_node_event(&config_arg, &mctl_node_info, &gesture_info);}//线面就是对两个socket进程监视和处理。 if ((fds[1].revents & POLLIN) == POLLIN) { /* EzTune Server */ int client_socket_id; client_socket_id = accept(ez_server_socket_id, (struct sockaddr *)&addr_client_inet, &addr_client_len); write(ez_cmd_pipe[1], &client_socket_id, sizeof(int)); } } if ((fds[2].revents & POLLIN) == POLLIN) { /* EzTune Prev Server */ int client_socket_id; client_socket_id = accept(ez_prev_server_socket_id, (struct sockaddr *)&addr_client_inet, &addr_client_len); write(ez_prev_cmd_pipe[1], &client_socket_id, sizeof(int)); } } } /* Else for Poll rc */ } while (1);} 下面进入配置线程创建的流程: //取出服务节点产生的事件,然后根据配置节点的名称,分发给各自独立的主控制线程1. static int qcamsvr_process_server_node_event(){//下命令让服务模块的事件出队列进行处理rc = ioctl(config_arg->server_fd, VIDIOC_DQEVENT, &v4l2_evt);if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_GES_RESP_V4L2){//如果是手势事件,则进行一系列的处理if (ctrl->type == MSM_V4L2_GES_OPEN) {//设置主控线程的接口p_gesture_info->cam_mctl.svr_ops.launch_mctl_thread = create_v4l2_conf_thread;//设置主控线程的退出接口p_gesture_info->cam_mctl.svr_ops.release_mctl_thread = destroy_v4l2_cam_conf_thread;//设置camera使能p_gesture_info->cam_mctl.svr_ops.camera_available = qcamsvr_camera_available; //设置服务设备文件的文件句柄p_gesture_info->cam_mctl.svr_ops.server_fd = config_arg->server_fd;//创建手势服务 status = p_gesture_info->gesture_lib.gesture_service_create( &p_gesture_info->cam_mctl, &p_gesture_info->observer);}else if (ctrl->type == MSM_V4L2_GES_CLOSE) {//消亡手势服务status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl)}if ((status == CAMERA_SUCCESS) && (ctrl->type != MSM_V4L2_GES_CLOSE)) { //如果成功,且文件打开,则向手势服务发送数据status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl); if (status != CAMERA_SUCCESS) { LOGE("gesture_service_send_data failed"); } } else { if (ctrl->type == MSM_V4L2_GES_CLOSE) { ctrl->status = CAM_CTRL_SUCCESS; } else { LOGE("gesture send failure message"); ctrl->status = CAM_CTRL_FAILED; }//将操作结果反馈给camera服务v4l2_ioctl.ioctl_ptr = ctrl;qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);//如果是camera事件,则进行一系列的处理}else if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2){if (ctrl->type == MSM_V4L2_OPEN) {//通过pipe进行一些初始化工作//创建一个核心的线程if ((tmp_mctl_struct->handle = create_v4l2_conf_thread(config_arg)) == NULL)//反馈结果给camera服务端ctrl->status = CAM_CTRL_SUCCESS; v4l2_ioctl.ioctl_ptr = ctrl; qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);}else if (ctrl->type == MSM_V4L2_CLOSE){//进行一些消亡工作//通过写一些pipeif (destroy_v4l2_cam_conf_thread(tmp_mctl_struct->handle) < 0) //消亡只线程ctrl->status = CAM_CTRL_SUCCESS; v4l2_ioctl.ioctl_ptr = ctrl;//反馈结果给camera服务qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);}else {//通过pipe写一些命令,等待配置返回}} //首先来看一下刚刚的线程创建函数void *create_v4l2_conf_thread(struct config_thread_arguments* arg){//核心工作就是创建了个线程rc = pthread_create(&pme->cam_mctl_thread_id, NULL, cam_mctl_thread, pme);}//下面进入创建的配置线程的主函数:static void *cam_mctl_thread(void *data)(mctl.c){//首先初始化需要监控的文件句柄 pipe_readfd = arg->read_fd; pipe_writefd = arg->write_fd; server_fd = arg->server_fd; ez_pipe_readfd = arg->ez_read_fd; ez_client_fd = -1; ez_prev_pipe_readfd = arg->ez_prev_read_fd; ez_prev_client_fd = -1;//向对应的配置节点下命令监控所有事件(此文件句柄具体标识什么意思暂时还没搞清楚)sub.type = V4L2_EVENT_ALL;rc = ioctl(cam_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);//下面开始进入循环的监控do { //文件句柄初始化 fds[0].fd = cam_fd; fds[0].events = POLLPRI; fds[1].fd = pipe_readfd; fds[1].events = POLLPRI | POLLIN; fds[2].fd = ez_pipe_readfd; fds[2].events = POLLIN; fds[3].fd = ez_client_fd; fds[3].events = POLLIN; fds[4].fd = ez_prev_pipe_readfd; fds[4].events = POLLIN; fds[5].fd = ez_prev_client_fd;fds[5].events = POLLIN;/* evt/msg from qcam server */if (ctrl->type == MSM_V4L2_CLOSE) {//关闭所有的资源config_shutdown_pp(pme->p_cfg_ctrl);//反馈结果给服务rc = mctl_send_ctrl_cmd_done(pme->p_cfg_ctrl, NULL, TRUE);}else { //此函数为用户控件的APP处理对应的命令 if (mctl_proc_v4l2_request(pme, ctrl) < 0)}/* evt/msg from config node */rc = ioctl(cam_fd, VIDIOC_DQEVENT, &v4l2_event);//下事件出队列的命令if (v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_DIV_FRAME_EVT_MSG) {//进程对应的帧转移mctl_pp_divert_frame(p_cfg_ctrl, (void *)&(event_data.isp_data.div_frame));}else if(v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT) {//处理后置的事件mctl_pp_proc_event(p_cfg_ctrl, (void *)&(event_data.isp_data.pp_event_info));}else if (v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_STAT_EVT_MSG) {//处理正常的事件消息mctl_proc_event_message (pme, isp_adsp);}else { CDBG_HIGH("%s: Error: should not be here", __func__);} /* evt/msg from eztune pipe */if (ez_client_fd > 0) mctl_eztune_server_connect(pme, ez_client_fd);/* evt/msg from eztune client */if (ez_client_fd > 0) {mctl_eztune_read_and_proc_cmd(EZ_MCTL_SOCKET_CMD); /* evt/msg from eztune prev pipe */if (ez_prev_client_fd > 0) mctl_eztune_prev_server_connect(pme, ez_prev_client_fd); } /* evt/msg from eztune prev client */ if ((fds[5].revents & POLLIN) == POLLIN) { if (ez_prev_client_fd > 0) { mctl_eztune_read_and_proc_cmd(EZ_MCTL_PREV_SOCKET_CMD); } }}wile(TRUE)//循环结束取消订阅所有消息if (ioctl(cam_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub) < 0)}先来看看camera在硬件抽象层的接口:主要是三点:1. preview:预览2. recording 录像3. picture 拍照模块接口函数: get_number_of_cameras: get_number_of_cameras, get_camera_info: get_camera_info, camera_info_t:typedef struct { int modes_supported;//支持的模式 int8_t camera_id;//id标识 cam_position_t position;//前摄还是后摄 uint32_t sensor_mount_angle;//角度}camera_info_t; 我们目前使用的高通8X平台:Camera模块:此模块有一个全局的camera服务结构体实例,用于全局管理各种子系统设备。子系统设备常见的有:enum msm_cam_subdev_type {CSIPHY_DEV,CSID_DEV,CSIC_DEV,ISPIF_DEV,VFE_DEV,AXI_DEV,VPE_DEV,SENSOR_DEV,ACTUATOR_DEV,EEPROM_DEV,GESTURE_DEV,};定义一个抽象的camera服务设备:struct msm_cam_server_dev {/* config node device*/struct platform_device *server_pdev;/* server node v4l2 device */struct v4l2_device v4l2_dev;struct video_device *video_dev;struct media_device media_dev; /* info of sensors successfully probed*/struct msm_camera_info camera_info;/* info of configs successfully created*/struct msm_cam_config_dev_info config_info;/* active working camera device - only one allowed at this time*/struct msm_cam_v4l2_device *pcam_active;/* number of camera devices opened*/atomic_t number_pcam_active;struct v4l2_queue_util server_command_queue; /* This queue used by the config thread to send responses back to the * control thread. It is accessed only from a process context. */struct msm_cam_server_queue server_queue[MAX_NUM_ACTIVE_CAMERA];uint32_t server_evt_id; struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];uint32_t mctl_handle_cnt; int use_count;/* all the registered ISP subdevice*/struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];/* info of MCTL nodes successfully probed*/struct msm_mctl_node_info mctl_node_info;struct mutex server_lock;struct mutex server_queue_lock;/*v4l2 subdevs*/struct v4l2_subdev *csiphy_device[MAX_NUM_CSIPHY_DEV];struct v4l2_subdev *csid_device[MAX_NUM_CSID_DEV];struct v4l2_subdev *csic_device[MAX_NUM_CSIC_DEV];struct v4l2_subdev *ispif_device;struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];struct v4l2_subdev *gesture_device;}; 从控制流的角度来分析下camera的流程。首先camera会启动一个daemon进程来进行核心的操作。启动daemon进程的地方:在init.target.rc文件中#start camera server as daemonservice qcamerasvr /system/bin/mm-qcamera-daemon class late_start user system group system camera inet生成此mm-qcamera-daemon bin档的地方:android\vendor\qcom\proprietary\mm-camera\apps\appslib\Android.mk此mk文件生成了mm-qcamera-daemon bin档 Daemon进程的入口函数:mian()(camdaemon.c)
抽象层到内核层的大致流程:抽象层主要通过server node和config node将command下到内核,对应的节点驱动将command通过事件队列进行管理。而daemon进程通过开启对应的线程,不停的对事件队列进行轮询,处理上层下的command 在main daemon thread中重要的任务:一:将sensor操作关联的硬件组件加载进来,还要加载一些必备的库,为camera的正式工作铺垫环境:① AXI_comp_create② sensor_comp_create③ flash_led_comp_create④ flash_strobe_comp_create⑤ CAMIF_comp_create⑥ VFE_comp_create⑦ ACTUATOR_comp_create⑧ eeprom_comp_create⑨ mctl_load_stats_proc_lib⑩ mctl_load_frame_proc_lib二.线程的循环工作线程,顾名思义,肯定有一个封闭的循环体,在循环体中做一些核心的操作而Daemon进程的主线程轮询服务节点的event queue,获取事件,纷发给各自的mctl threadDaemon进行的主线程主要处理一下基类事件“① MSM_GES_RESP_V4L2 :Open:主要进行初始化,铺垫环境,开启处理camera细节活动的线程Close:进行一些善后工作② MSM_CAM_RESP_V4L2:处理open和colseOpen:主要进行初始化,铺垫环境,开启处理camera细节活动的线程Close:进行一些善后工作③ 其他一些事件都是通过pipe通信直接写入到①②两点创建的线程中(send command through pipe and wait for config to return)在mctl thread中重要的任务:一. 打开confing节点文件二. 调用create_camfd_receive_socket猜测是与硬件抽象层进行直接通信的三. 创建mctl_pp_poll_thread线程,四. 初始化camera的几个feature: ①zoom_init_ctrl ②bestshot_init ③hdr_init五.通过pipe通信获取server节点的控制事件,事件由Daemon进程的主控线程获取并且通过pipe传递过来六.通过监测config节点的事件获取config节点对应的控制command主要监测三类事件:① MSM_CAM_RESP_DIV_FRAME_EVT_MSG② MSM_CAM_RESP_MCTL_PP_EVENT③ MSM_CAM_RESP_STAT_EVT_MSG将这三个事件以command的形式,通过pipe通信发送到(一)中创建的PP线程中在mctl_pp_poll_thread中重要的任务:一:对几个pipe文件进行监测,与其他线程进行交互几种事件:①/* Events on pipe between mctl thread - mctl pp thread */②/* Events on user created socket */③/* Events on mctl pp node */④/* Events on pipe between mctl pp thread and c2d thread */
http://blog.csdn.net/qq69696698/article/details/73993211、Camera成像原理介绍Camera工作流程图 href="http://hi.csdn.net/attachment/201008/15/0_12818802315azb.gif" target=_blank>
Camera的成像原理可以简单概括如下:景物(SCENE)通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为电信号,经过A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯片(DSP)中加工处理,再通过IO接口传输到CPU中处理,通过DISPLAY就可以看到图像了。电荷耦合器件(CCD)或互补金属氧化物半导体(CMOS)接收光学镜头传递来的影像,经模/数转换器(A/D)转换成数字信号,经过编码后存储。流程如下:
1、CCD/CMOS将被摄体的光信号转变为电信号—电子图像(模拟信号)
2、由模/数转换器(ADC)芯片来将模拟信号转化为数字信号
3、数字信号形成后,由DSP或编码库对信号进行压缩并转化为特定的图像文件格式储存数码相机的光学镜头与传统相机相同,将影像聚到感光器件上,即(光)电荷耦合器件(CCD) 。CCD替代了传统相机中的感光胶片的位置,其功能是将光信号转换成电信号,与电视摄像相同。CCD是半导体器件,是数码相机的核心,其内含器件的单元数量决定了数码相机的成像质量——像素,单元越多,即像素数高,成像质量越好,通常情况下像素的高低代表了数码相机的档次和技术指标。2、Android Camera框架Android的Camera子系统提供一个拍照和录制视频的框架。它将Camera的上层应用与Application Framework、用户库串接起来,而正是这个用户库来与Camera的硬件层通信,从而实现操作camera硬件。
3、Android Camera的代码结构Android的Camera代码主要在以下的目录中:
Camera的JAVA部分
packages/apps/Camera/。其中Camera.java是主要实现的文件。这部分内容编译成为目标是Camera.apk
com.android.camera这个包,几个主要的类文件如下:
PhotoViewer:GalleryPicker.java(所有图片集)--->ImageGallery.java(某个Folder下图片列表)--->ViewImage.java(看某张具体图片)
VideoPlayer:GalleryPicker.java(所有视频集) --->MovieView.java(看某一个视频)
Camera:Camera.java(Camera取景及拍照)
VideoCamera:VideoCamera.java(VideoCamera取景及摄像)
Camera的framework供上层应用调用的部分 base/core/java/android/hardware/Camera.java这部分目标是framework.jar Camera的JNI部分
frameworks/base/core/jni/android_hardware_Camera.cpp
这部分内容编译成为目标是libandroid_runtime.so。Camera UI库部分
frameworks/base/libs/ui/camera
这部分的内容被编译成库libcamera_client.so。Camera服务部分
frameworks/base/camera/libcameraservice/
这部分内容被编译成库libcameraservice.so。Camera HAL层部分
hardware/msm7k/libcamera
或
vendor/qcom/android-open/libcamera2
为了实现一个具体功能的Camera,在HAL层需要一个硬件相关的Camera库(例如通过调用video for linux驱动程序和Jpeg编码程序实现或者直接用各个chip厂商实现的私有库来实现,比如Qualcomm实现的libcamera.so和libqcamera.so),实现CameraHardwareInterface规定的接口,来调用相关的库,驱动相关的driver,实现对camera硬件的操作。这个库将被Camera的服务库libcameraservice.so调用。未完待续在下一篇中,我会以两条路径来详细介绍Camera HAL的实现:自己依据V4l2规范来实现CameraHardwareInterface; Qualcomm的Camera架构(QualcommCameraHardware和mm-camera/mm-still)。当然,在涉及到Qualcomm私有库部分,为避免不必要的麻烦,我会一笔带过。敬请见谅!
Camera先看一下抽象层的主要流程:首先启动一个守护进程Main()(camdaemon.c)int qcamsvr_start(void)( qcamsvr.c){1. server_fd = open(server_dev_name, O_RDWR);//打开服务对应的文件节点2. if (mctl_load_comps()) //加载所有需要的组件3. rc = qcamsvr_load_gesture_lib(&gesture_info.gesture_lib);//加载手势库4. ez_server_socket_id = eztune_setup_server("127.0.0.1", "55555");if (pipe(ez_cmd_pipe)ez_prev_server_socket_id = eztune_setup_server("127.0.0.1", "55556");if(pipe(ez_prev_cmd_pipe)//创建两个socket端口,同时建立两个pipe文件对两个端口进行监控5. if (get_mctl_node_info(server_fd, &mctl_node_info))//通过服务节点获取服务的相关信息{//此处获取的是内核中调用msm_sensor_register()注册的sensor节点信息}6. sub.type = V4L2_EVENT_ALL;rc = ioctl(server_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);//通过服务设备文件的ioctl接口,订阅所有的事件7. config_arg.server_fd = server_fd; config_arg.ez_read_fd = ez_cmd_pipe[0]; config_arg.ez_write_fd = ez_cmd_pipe[1]; config_arg.ez_prev_read_fd = ez_prev_cmd_pipe[0]; config_arg.ez_prev_write_fd = ez_prev_cmd_pipe[1];//初始化配置线程的参数8.下面就是一个循环,对这几个文件进行poll do { fds[0].fd = server_fd; fds[0].events = POLLPRI; fds[1].fd = ez_server_socket_id; fds[1].events = POLLIN; fds[2].fd = ez_prev_server_socket_id; fds[2].events = POLLIN; rc = poll(fds, 3, timeoutms);if (fds[0].revents & POLLPRI) { /* Server Node Wake Up * //对服务的设备文件进行监视,当遇到打开事件的时候,立即创建一个配置线程 rc = qcamsvr_process_server_node_event(&config_arg, &mctl_node_info, &gesture_info);}//线面就是对两个socket进程监视和处理。 if ((fds[1].revents & POLLIN) == POLLIN) { /* EzTune Server */ int client_socket_id; client_socket_id = accept(ez_server_socket_id, (struct sockaddr *)&addr_client_inet, &addr_client_len); write(ez_cmd_pipe[1], &client_socket_id, sizeof(int)); } } if ((fds[2].revents & POLLIN) == POLLIN) { /* EzTune Prev Server */ int client_socket_id; client_socket_id = accept(ez_prev_server_socket_id, (struct sockaddr *)&addr_client_inet, &addr_client_len); write(ez_prev_cmd_pipe[1], &client_socket_id, sizeof(int)); } } } /* Else for Poll rc */ } while (1);} 下面进入配置线程创建的流程: //取出服务节点产生的事件,然后根据配置节点的名称,分发给各自独立的主控制线程1. static int qcamsvr_process_server_node_event(){//下命令让服务模块的事件出队列进行处理rc = ioctl(config_arg->server_fd, VIDIOC_DQEVENT, &v4l2_evt);if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_GES_RESP_V4L2){//如果是手势事件,则进行一系列的处理if (ctrl->type == MSM_V4L2_GES_OPEN) {//设置主控线程的接口p_gesture_info->cam_mctl.svr_ops.launch_mctl_thread = create_v4l2_conf_thread;//设置主控线程的退出接口p_gesture_info->cam_mctl.svr_ops.release_mctl_thread = destroy_v4l2_cam_conf_thread;//设置camera使能p_gesture_info->cam_mctl.svr_ops.camera_available = qcamsvr_camera_available; //设置服务设备文件的文件句柄p_gesture_info->cam_mctl.svr_ops.server_fd = config_arg->server_fd;//创建手势服务 status = p_gesture_info->gesture_lib.gesture_service_create( &p_gesture_info->cam_mctl, &p_gesture_info->observer);}else if (ctrl->type == MSM_V4L2_GES_CLOSE) {//消亡手势服务status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl)}if ((status == CAMERA_SUCCESS) && (ctrl->type != MSM_V4L2_GES_CLOSE)) { //如果成功,且文件打开,则向手势服务发送数据status = p_gesture_info->gesture_lib.gesture_service_send_data(ctrl); if (status != CAMERA_SUCCESS) { LOGE("gesture_service_send_data failed"); } } else { if (ctrl->type == MSM_V4L2_GES_CLOSE) { ctrl->status = CAM_CTRL_SUCCESS; } else { LOGE("gesture send failure message"); ctrl->status = CAM_CTRL_FAILED; }//将操作结果反馈给camera服务v4l2_ioctl.ioctl_ptr = ctrl;qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);//如果是camera事件,则进行一系列的处理}else if (v4l2_evt.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_V4L2){if (ctrl->type == MSM_V4L2_OPEN) {//通过pipe进行一些初始化工作//创建一个核心的线程if ((tmp_mctl_struct->handle = create_v4l2_conf_thread(config_arg)) == NULL)//反馈结果给camera服务端ctrl->status = CAM_CTRL_SUCCESS; v4l2_ioctl.ioctl_ptr = ctrl; qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);}else if (ctrl->type == MSM_V4L2_CLOSE){//进行一些消亡工作//通过写一些pipeif (destroy_v4l2_cam_conf_thread(tmp_mctl_struct->handle) < 0) //消亡只线程ctrl->status = CAM_CTRL_SUCCESS; v4l2_ioctl.ioctl_ptr = ctrl;//反馈结果给camera服务qcamsvr_send_ctrl_cmd_done(config_arg->server_fd, &v4l2_ioctl);}else {//通过pipe写一些命令,等待配置返回}} //首先来看一下刚刚的线程创建函数void *create_v4l2_conf_thread(struct config_thread_arguments* arg){//核心工作就是创建了个线程rc = pthread_create(&pme->cam_mctl_thread_id, NULL, cam_mctl_thread, pme);}//下面进入创建的配置线程的主函数:static void *cam_mctl_thread(void *data)(mctl.c){//首先初始化需要监控的文件句柄 pipe_readfd = arg->read_fd; pipe_writefd = arg->write_fd; server_fd = arg->server_fd; ez_pipe_readfd = arg->ez_read_fd; ez_client_fd = -1; ez_prev_pipe_readfd = arg->ez_prev_read_fd; ez_prev_client_fd = -1;//向对应的配置节点下命令监控所有事件(此文件句柄具体标识什么意思暂时还没搞清楚)sub.type = V4L2_EVENT_ALL;rc = ioctl(cam_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);//下面开始进入循环的监控do { //文件句柄初始化 fds[0].fd = cam_fd; fds[0].events = POLLPRI; fds[1].fd = pipe_readfd; fds[1].events = POLLPRI | POLLIN; fds[2].fd = ez_pipe_readfd; fds[2].events = POLLIN; fds[3].fd = ez_client_fd; fds[3].events = POLLIN; fds[4].fd = ez_prev_pipe_readfd; fds[4].events = POLLIN; fds[5].fd = ez_prev_client_fd;fds[5].events = POLLIN;/* evt/msg from qcam server */if (ctrl->type == MSM_V4L2_CLOSE) {//关闭所有的资源config_shutdown_pp(pme->p_cfg_ctrl);//反馈结果给服务rc = mctl_send_ctrl_cmd_done(pme->p_cfg_ctrl, NULL, TRUE);}else { //此函数为用户控件的APP处理对应的命令 if (mctl_proc_v4l2_request(pme, ctrl) < 0)}/* evt/msg from config node */rc = ioctl(cam_fd, VIDIOC_DQEVENT, &v4l2_event);//下事件出队列的命令if (v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_DIV_FRAME_EVT_MSG) {//进程对应的帧转移mctl_pp_divert_frame(p_cfg_ctrl, (void *)&(event_data.isp_data.div_frame));}else if(v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_MCTL_PP_EVENT) {//处理后置的事件mctl_pp_proc_event(p_cfg_ctrl, (void *)&(event_data.isp_data.pp_event_info));}else if (v4l2_event.type == V4L2_EVENT_PRIVATE_START + MSM_CAM_RESP_STAT_EVT_MSG) {//处理正常的事件消息mctl_proc_event_message (pme, isp_adsp);}else { CDBG_HIGH("%s: Error: should not be here", __func__);} /* evt/msg from eztune pipe */if (ez_client_fd > 0) mctl_eztune_server_connect(pme, ez_client_fd);/* evt/msg from eztune client */if (ez_client_fd > 0) {mctl_eztune_read_and_proc_cmd(EZ_MCTL_SOCKET_CMD); /* evt/msg from eztune prev pipe */if (ez_prev_client_fd > 0) mctl_eztune_prev_server_connect(pme, ez_prev_client_fd); } /* evt/msg from eztune prev client */ if ((fds[5].revents & POLLIN) == POLLIN) { if (ez_prev_client_fd > 0) { mctl_eztune_read_and_proc_cmd(EZ_MCTL_PREV_SOCKET_CMD); } }}wile(TRUE)//循环结束取消订阅所有消息if (ioctl(cam_fd, VIDIOC_UNSUBSCRIBE_EVENT, &sub) < 0)}先来看看camera在硬件抽象层的接口:主要是三点:1. preview:预览2. recording 录像3. picture 拍照模块接口函数: get_number_of_cameras: get_number_of_cameras, get_camera_info: get_camera_info, camera_info_t:typedef struct { int modes_supported;//支持的模式 int8_t camera_id;//id标识 cam_position_t position;//前摄还是后摄 uint32_t sensor_mount_angle;//角度}camera_info_t; 我们目前使用的高通8X平台:Camera模块:此模块有一个全局的camera服务结构体实例,用于全局管理各种子系统设备。子系统设备常见的有:enum msm_cam_subdev_type {CSIPHY_DEV,CSID_DEV,CSIC_DEV,ISPIF_DEV,VFE_DEV,AXI_DEV,VPE_DEV,SENSOR_DEV,ACTUATOR_DEV,EEPROM_DEV,GESTURE_DEV,};定义一个抽象的camera服务设备:struct msm_cam_server_dev {/* config node device*/struct platform_device *server_pdev;/* server node v4l2 device */struct v4l2_device v4l2_dev;struct video_device *video_dev;struct media_device media_dev; /* info of sensors successfully probed*/struct msm_camera_info camera_info;/* info of configs successfully created*/struct msm_cam_config_dev_info config_info;/* active working camera device - only one allowed at this time*/struct msm_cam_v4l2_device *pcam_active;/* number of camera devices opened*/atomic_t number_pcam_active;struct v4l2_queue_util server_command_queue; /* This queue used by the config thread to send responses back to the * control thread. It is accessed only from a process context. */struct msm_cam_server_queue server_queue[MAX_NUM_ACTIVE_CAMERA];uint32_t server_evt_id; struct msm_cam_server_mctl_inst mctl[MAX_NUM_ACTIVE_CAMERA];uint32_t mctl_handle_cnt; int use_count;/* all the registered ISP subdevice*/struct msm_isp_ops *isp_subdev[MSM_MAX_CAMERA_CONFIGS];/* info of MCTL nodes successfully probed*/struct msm_mctl_node_info mctl_node_info;struct mutex server_lock;struct mutex server_queue_lock;/*v4l2 subdevs*/struct v4l2_subdev *csiphy_device[MAX_NUM_CSIPHY_DEV];struct v4l2_subdev *csid_device[MAX_NUM_CSID_DEV];struct v4l2_subdev *csic_device[MAX_NUM_CSIC_DEV];struct v4l2_subdev *ispif_device;struct v4l2_subdev *vfe_device[MAX_NUM_VFE_DEV];struct v4l2_subdev *axi_device[MAX_NUM_AXI_DEV];struct v4l2_subdev *vpe_device[MAX_NUM_VPE_DEV];struct v4l2_subdev *gesture_device;}; 从控制流的角度来分析下camera的流程。首先camera会启动一个daemon进程来进行核心的操作。启动daemon进程的地方:在init.target.rc文件中#start camera server as daemonservice qcamerasvr /system/bin/mm-qcamera-daemon class late_start user system group system camera inet生成此mm-qcamera-daemon bin档的地方:android\vendor\qcom\proprietary\mm-camera\apps\appslib\Android.mk此mk文件生成了mm-qcamera-daemon bin档 Daemon进程的入口函数:mian()(camdaemon.c)
一个camera的守护进程在init进程中,开启的一个service |
此线程与具体的sensor相关联,负责对sensor进行具体细节的操作 |
此为daemon进程的主线程,从server node收集事件,纷发给mctl thread,根据config的name,与server节点进行队列,不断轮询其事件队列,获取command,进行全局处理 |
mctl_pp_poll_thread |
mctl thread |
main daemon thread |
Daemon |
此线程与kernel中config节点进行通信,轮询节点的消息队列中获得command,进行全局处理 (每一个config节点都对应一个mctl thread) |
抽象层到内核层的大致流程:抽象层主要通过server node和config node将command下到内核,对应的节点驱动将command通过事件队列进行管理。而daemon进程通过开启对应的线程,不停的对事件队列进行轮询,处理上层下的command 在main daemon thread中重要的任务:一:将sensor操作关联的硬件组件加载进来,还要加载一些必备的库,为camera的正式工作铺垫环境:① AXI_comp_create② sensor_comp_create③ flash_led_comp_create④ flash_strobe_comp_create⑤ CAMIF_comp_create⑥ VFE_comp_create⑦ ACTUATOR_comp_create⑧ eeprom_comp_create⑨ mctl_load_stats_proc_lib⑩ mctl_load_frame_proc_lib二.线程的循环工作线程,顾名思义,肯定有一个封闭的循环体,在循环体中做一些核心的操作而Daemon进程的主线程轮询服务节点的event queue,获取事件,纷发给各自的mctl threadDaemon进行的主线程主要处理一下基类事件“① MSM_GES_RESP_V4L2 :Open:主要进行初始化,铺垫环境,开启处理camera细节活动的线程Close:进行一些善后工作② MSM_CAM_RESP_V4L2:处理open和colseOpen:主要进行初始化,铺垫环境,开启处理camera细节活动的线程Close:进行一些善后工作③ 其他一些事件都是通过pipe通信直接写入到①②两点创建的线程中(send command through pipe and wait for config to return)在mctl thread中重要的任务:一. 打开confing节点文件二. 调用create_camfd_receive_socket猜测是与硬件抽象层进行直接通信的三. 创建mctl_pp_poll_thread线程,四. 初始化camera的几个feature: ①zoom_init_ctrl ②bestshot_init ③hdr_init五.通过pipe通信获取server节点的控制事件,事件由Daemon进程的主控线程获取并且通过pipe传递过来六.通过监测config节点的事件获取config节点对应的控制command主要监测三类事件:① MSM_CAM_RESP_DIV_FRAME_EVT_MSG② MSM_CAM_RESP_MCTL_PP_EVENT③ MSM_CAM_RESP_STAT_EVT_MSG将这三个事件以command的形式,通过pipe通信发送到(一)中创建的PP线程中在mctl_pp_poll_thread中重要的任务:一:对几个pipe文件进行监测,与其他线程进行交互几种事件:①/* Events on pipe between mctl thread - mctl pp thread */②/* Events on user created socket */③/* Events on mctl pp node */④/* Events on pipe between mctl pp thread and c2d thread */
http://blog.csdn.net/qq69696698/article/details/73993211、Camera成像原理介绍Camera工作流程图 href="http://hi.csdn.net/attachment/201008/15/0_12818802315azb.gif" target=_blank>
Camera的成像原理可以简单概括如下:景物(SCENE)通过镜头(LENS)生成的光学图像投射到图像传感器(Sensor)表面上,然后转为电信号,经过A/D(模数转换)转换后变为数字图像信号,再送到数字信号处理芯片(DSP)中加工处理,再通过IO接口传输到CPU中处理,通过DISPLAY就可以看到图像了。电荷耦合器件(CCD)或互补金属氧化物半导体(CMOS)接收光学镜头传递来的影像,经模/数转换器(A/D)转换成数字信号,经过编码后存储。流程如下:
1、CCD/CMOS将被摄体的光信号转变为电信号—电子图像(模拟信号)
2、由模/数转换器(ADC)芯片来将模拟信号转化为数字信号
3、数字信号形成后,由DSP或编码库对信号进行压缩并转化为特定的图像文件格式储存数码相机的光学镜头与传统相机相同,将影像聚到感光器件上,即(光)电荷耦合器件(CCD) 。CCD替代了传统相机中的感光胶片的位置,其功能是将光信号转换成电信号,与电视摄像相同。CCD是半导体器件,是数码相机的核心,其内含器件的单元数量决定了数码相机的成像质量——像素,单元越多,即像素数高,成像质量越好,通常情况下像素的高低代表了数码相机的档次和技术指标。2、Android Camera框架Android的Camera子系统提供一个拍照和录制视频的框架。它将Camera的上层应用与Application Framework、用户库串接起来,而正是这个用户库来与Camera的硬件层通信,从而实现操作camera硬件。
3、Android Camera的代码结构Android的Camera代码主要在以下的目录中:
Camera的JAVA部分
packages/apps/Camera/。其中Camera.java是主要实现的文件。这部分内容编译成为目标是Camera.apk
com.android.camera这个包,几个主要的类文件如下:
PhotoViewer:GalleryPicker.java(所有图片集)--->ImageGallery.java(某个Folder下图片列表)--->ViewImage.java(看某张具体图片)
VideoPlayer:GalleryPicker.java(所有视频集) --->MovieView.java(看某一个视频)
Camera:Camera.java(Camera取景及拍照)
VideoCamera:VideoCamera.java(VideoCamera取景及摄像)
Camera的framework供上层应用调用的部分 base/core/java/android/hardware/Camera.java这部分目标是framework.jar Camera的JNI部分
frameworks/base/core/jni/android_hardware_Camera.cpp
这部分内容编译成为目标是libandroid_runtime.so。Camera UI库部分
frameworks/base/libs/ui/camera
这部分的内容被编译成库libcamera_client.so。Camera服务部分
frameworks/base/camera/libcameraservice/
这部分内容被编译成库libcameraservice.so。Camera HAL层部分
hardware/msm7k/libcamera
或
vendor/qcom/android-open/libcamera2
为了实现一个具体功能的Camera,在HAL层需要一个硬件相关的Camera库(例如通过调用video for linux驱动程序和Jpeg编码程序实现或者直接用各个chip厂商实现的私有库来实现,比如Qualcomm实现的libcamera.so和libqcamera.so),实现CameraHardwareInterface规定的接口,来调用相关的库,驱动相关的driver,实现对camera硬件的操作。这个库将被Camera的服务库libcameraservice.so调用。未完待续在下一篇中,我会以两条路径来详细介绍Camera HAL的实现:自己依据V4l2规范来实现CameraHardwareInterface; Qualcomm的Camera架构(QualcommCameraHardware和mm-camera/mm-still)。当然,在涉及到Qualcomm私有库部分,为避免不必要的麻烦,我会一笔带过。敬请见谅!
相关文章推荐
- 使用Java开发高性能网站需要关注的那些事儿
- 怎样实现下拉合作网站登录界面
- MySQL高可用之:MySQL-MMM
- ODI学习笔记2--ODI产品架构
- OpenCV从入门到放弃(二):架构和上手
- iOS开发常用国外网站清单
- 展示模式架构比较MVP(SC),MVP(PV),PM,MVVM和MVC
- 想转行做运营人?这些事 你要知道
- 大型网站系统架构演化之路
- 构建高可用ZooKeeper集群
- 关于百度机器人搜索你网站的页面权限设置
- 网站性能优化概要
- 不错的学习网站
- 虚拟化基础架构Windows 2008篇之10-使用WDS安装Windows 7
- 虚拟化基础架构Windows 2008篇之9-配置Windows部署服务
- 虚拟化基础架构Windows 2008篇之8-添加启动映像
- 一些软件测试学习网站推荐
- 虚拟化基础架构Windows 2008篇之7-添加其他操作系统的安装镜像
- 虚拟化基础架构Windows 2008篇之6-启动Windows部署服务
- 虚拟化基础架构Windows 2008篇之5-安装Windows部署服务