Camera
Let's take a look at the main flow of the abstraction layer:
Start a daemon process First
int Qcamsvr_start (void) (QCAMSVR.C)
{
1. server_fd = Open (Server_dev_name, O_RDWR);//Open the file node for the service
2. if (Mctl_load_comps ())//load all required components
3. rc = Qcamsvr_load_gesture_lib (&gesture_info.gesture_lib);//Load Gesture Library
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)
Create two socket ports and set up two pipe files to monitor two ports
5. if (Get_mctl_node_info (SERVER_FD, &mctl_node_info))//access information about the service via the service node
{
This gets the sensor node information that is registered in the kernel called Msm_sensor_register ()
}
6. Sub.type = V4l2_event_all;
rc = IOCTL (SERVER_FD, vidioc_subscribe_event, &sub);//subscribe to all events via the IOCTL interface of the service device file
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];//Initialization of parameters for the configuration thread
8. Here is a loop that poll the files
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 *
Monitor the service's device files and create a configuration thread as soon as an open event is encountered
rc = Qcamsvr_process_server_node_event (&config_arg, &mctl_node_info,
&gesture_info);
}
The line surface is the monitoring and processing of two socket processes .
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);
}
Below goes the process of configuring thread creation:
Take out the events generated by the service node, and then distribute them to separate master control threads based on the name of the configuration node
1. static int qcamsvr_process_server_node_event ()
{
command to process the event out queue of the service module
rc = IOCTL (CONFIG_ARG->SERVER_FD, vidioc_dqevent, &v4l2_evt);
if (V4l2_evt.type = = V4l2_event_private_start + msm_ges_resp_v4l2)
{
If it is a gesture event, a series of processing
if (Ctrl->type = = Msm_v4l2_ges_open) {
To set the interface for a master thread
P_gesture_info->cam_mctl.svr_ops.launch_mctl_thread =
Create_v4l2_conf_thread;
To set the exit interface for a master thread
P_gesture_info->cam_mctl.svr_ops.release_mctl_thread =
Destroy_v4l2_cam_conf_thread;
To set the camera enable
P_gesture_info->cam_mctl.svr_ops.camera_available =
qcamsvr_camera_available;
Set file handles for service device files
P_GESTURE_INFO->CAM_MCTL.SVR_OPS.SERVER_FD = config_arg->server_fd;
Create a gesture service
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) {
Vanishing gesture Service
Status = P_gesture_info->gesture_lib.gesture_service_send_data (ctrl)
}
if (status = = Camera_success) &&
(Ctrl->type! = msm_v4l2_ges_close)) {
If successful and the file is open, send data to the gesture service
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;
}
Feedback the results of the operation to the camera service
V4l2_ioctl.ioctl_ptr = CTRL;
Qcamsvr_send_ctrl_cmd_done (CONFIG_ARG->SERVER_FD, &v4l2_ioctl);
If it is a camera event, a series of processing
}
else if (V4l2_evt.type = = V4l2_event_private_start + msm_cam_resp_v4l2)
{
if (Ctrl->type = = Msm_v4l2_open) {
Some initialization work through the pipe
To create a core thread
if (Tmp_mctl_struct->handle =
Feedback results to the camera server
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) {
Do some dying work
By writing some pipe
if (Destroy_v4l2_cam_conf_thread (Tmp_mctl_struct->handle) < 0)//extinct only thread
Ctrl->status = cam_ctrl_success;
V4l2_ioctl.ioctl_ptr = CTRL;
Feedback results to the camera service
Qcamsvr_send_ctrl_cmd_done (CONFIG_ARG->SERVER_FD, &v4l2_ioctl);
}
else {
Write some commands through the pipe and wait for the configuration to return
}
}
Let's take a look at just the thread creation function
void *create_v4l2_conf_thread (struct config_thread_arguments* arg)
{
The core job is to create a thread
rc = Pthread_create (&pme->cam_mctl_thread_id, NULL, Cam_mctl_thread, PME);
}
The following goes into the main function of the created configuration thread:
static void *cam_mctl_thread (void *data) (MCTL.C)
{
First initialize the file handle that needs to be monitored
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;
Monitor all events to the corresponding configuration node (this file handle specifically identifies what the meaning is not yet clear)
Sub.type = V4l2_event_all;
rc = IOCTL (CAM_FD, vidioc_subscribe_event, &sub);
The following begins the monitoring of the loop
do {
File Handle Initialization
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) {
Close all Resources
CONFIG_SHUTDOWN_PP (Pme->p_cfg_ctrl);
Feedback results to the service
rc = Mctl_send_ctrl_cmd_done (Pme->p_cfg_ctrl, NULL, TRUE);
}
else {
This function handles the corresponding command for the user control's app
if (Mctl_proc_v4l2_request (PME, CTRL) < 0)
}
/* evt/msg from config node */
rc = IOCTL (CAM_FD, vidioc_dqevent, &v4l2_event);//command to queue the event out
if (V4l2_event.type = =
V4l2_event_private_start + msm_cam_resp_div_frame_evt_msg) {
process -corresponding frame transfer
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) {
Handling post-event events
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) {
Handling of normal event messages
Mctl_proc_event_message (PME, ISP_ADSP);
}
else {
Cdbg_high ("%s:error:should not being 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)
End of loop unsubscribe all messages
if (IOCTL (CAM_FD, Vidioc_unsubscribe_event, &sub) < 0)
}
Let's take a look at the interface of camera in the hardware abstraction layer:
The main point is three:
1. Preview: Previewing
2. Recording video
3. Picture photo
Module interface functions:
Get_number_of_cameras:get_number_of_cameras,
Get_camera_info:get_camera_info,
camera_info_t:
typedef struct {
int modes_supported;//Supported mode
int8_t CAMERA_ID;//ID logo
Cam_position_t position;//before or after the camera
uint32_t sensor_mount_angle;//Angle
}camera_info_t;
We currently use the Qualcomm 8X platform:
Camera module:
This module has a global instance of the camera service structure that is used to globally manage various subsystem devices.
subsystem devices are common:
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,
};
Define an abstract camera service device:
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 the 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;
};
The process of the next camera is analyzed from the perspective of the control flow.
First, the camera initiates a daemon process to perform the core operation.
Where to start the daemon process :
In the Init.target.rc file
#start Camera Server as Daemon
Service Qcamerasvr/system/bin/mm-qcamera-daemon
Class Late_start
User System
Group System Camera inet
Where this Mm-qcamera-daemon bin file is generated:
Android\vendor\qcom\proprietary\mm-camera\apps\appslib\android.mk
This MK file generates the Mm-qcamera-daemon bin file
Entry function for Daemon process : Mian () (CAMDAEMON.C)
A camera daemon in the init process , opens a service |
This thread is associated with a specific sensor and is responsible for the specific details of the sensor operation |
This is the main thread of the daemon process , which collects events from server node, issues mctl thread, queues with the server node based on the name of Config, keeps polling its event queue, gets command, and handles global processing |
This thread communicates with the Config node in the kernel, receives a command in the message queue of the polling node, and processes it globally (each config node corresponds to a mctl thread) |
The approximate process of abstraction layer to kernel layer:
The abstraction layer will command down to the kernel through server node and Config node, and the corresponding node driver will manage the command through the event queue.
The daemon process , by opening the corresponding thread, keeps polling the event queue and handles the command on the upper level.
Important tasks in main daemon thread:
One: Load the hardware components associated with the sensor operation, and load some necessary libraries to pave the environment for the camera's formal work:
①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
Two Looping work for threads
threads, as the name implies, must have a closed loop body, doing some core operations in the loop body
While the main thread of the daemon process Polls the service node for the event queue, gets events that are sent to their mctl thread
The main thread of the daemon mainly handles the base class event "
①MSM_GES_RESP_V4L2:
Open: Primary initialization, foreshadowing the environment, open the thread that handles camera detail activity
Close: Perform some aftercare work
②MSM_CAM_RESP_V4L2: Handling Open and Colse
Open: Primary initialization, foreshadowing the environment, open the thread that handles camera detail activity
Close: Perform some aftercare work
③ other events are written directly to the line created by the ①② two point via pipe communication approached (send command through pipe and wait for config to return)
Important tasks in Mctl thread:
One. Open the Confing node file
Two. Call Create_camfd_receive_socket guess is a direct communication with the hardware abstraction layer
Three. Create a mctl_pp_poll_thread thread,
Four. Initialize several feature of the camera:
①zoom_init_ctrl
②bestshot_init
③hdr_init
Five. Get the control events of the server node through pipe communication, the event is obtained by the master thread of the daemon process and passed through the pipe.
Six Get the control command for the Config node by monitoring the events of the Config node
Three main types of events are monitored:
①msm_cam_resp_div_frame_evt_msg
②msm_cam_resp_mctl_pp_event
③msm_cam_resp_stat_evt_msg
The three events are sent to the PP thread created in (a) by pipe communication in the form of a command.
Important tasks in the Mctl_pp_poll_thread:
One: monitor several pipe files and interact with other threads
Several events:
①/* 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 */
Analysis of Qualcomm 8X camera daemon Process