解析高通vendor层mct框架

凡越底层的代码,更能体现代码的精髓所在 — 数据结构 + 算法模型,所以在研究其代码时,可以先重点关注其数据结构,能更好的帮助我们解析其背后的原理逻辑!今天来分析一下高通的camera vendor下与camera hal相关的部分,mct模块,mct算是其中一个基础模块,其他所有的sensor、isp、imagelib等都会使用mct,所以对它的理解至关重要,更能帮助我们理解其他模块


基础数据结构体

mct_module_t

mct_module_t是mct的重要模块,几乎其他所有结构体和代码都和它由关系;

_mct_module就是mct_module_t的底层实现
struct _mct_module {mct_object_t      object;mct_list_t        *type_list;   //相对于stream的此module的类型列表mct_list_t        *srcports;   //源端口,发出端口unsigned short    numsrcports; //端口数量mct_list_t        *sinkports;     //汇入端口,接收数据unsigned short    numsinkports;   //端口数量void              *module_private;  //私有变量,每个module该类型不同,如sensor它为module_sensor_ctrl_rpthread_mutex_t   type_list_lock; //线程的互斥量/* 虚函数,所有的模块都必须要实现这些虚函数 */mct_module_process_event_func    process_event;mct_module_set_mod_func          set_mod;mct_module_query_mod_func        query_mod;mct_module_request_port_function request_new_port;mct_module_start_session         start_session;mct_module_stop_session          stop_session;mct_module_set_session_data      set_session_data;mct_module_get_session_data      get_session_data;
};

mct_module可以作为stream的子对象,相对于stream来说这个mct_module是什么类型,source、sink或者中间

typedef struct {stream表示identityunsigned int identity;相对于stream,mct_module类型type   mct_module_type_t type;
} mct_module_type_identity_t;

mct_object_t

mct中很多结构体都会有父或者子对象,如何形成父子对象映射关系,就是通过mct_object_t来实现的;因为很多结构体都会拥有或者间接拥有一个mct_object_t成员,所以就可能通过内部引用找到自己的mct_object_t来设置父子关系

struct _mct_object {                                                                                                                                                                                                                                                                     一个object匹配一个pipeline,父子规则如下:一个pipeline可能有多个子对象stream一个stream可能有多个子对象modules一个module可能有多个子Port一个port可能有多个子stream或者session,port必须并且只有一个父Modulemoudle可能有多个父streamstream有且仅有一个父pipelinemct_list_t       *parent; 表示自己的父对象有哪些,是一个链表形式,说明可以有多个unsigned int     parentsnum;mct_list_t       *children; 标明自己的子对象有哪些,同上unsigned int     childrennum;char             *name; /* individual object's name              *//* invidual Object information */int              refcount; /* individual object's reference count   *//* Note: For future usage,* object LOCK, should be initialized to PTHREAD_MUTEX_INITIALIZER */pthread_mutex_t  lock;unsigned int     flags;void            *priv;
};/*
mct list的node节点,双向链表,其中data有可能有两种结构体:
相对于各个module模块来说,其类型为mct_module_t
相对一个session会话来说,是mct_controller_t类型
相对于bus总线上的消息,是mct_bus_msg_t*/
struct _mct_list {void         *data;       mct_list_t   *prev;mct_list_t   **next;   /*理解为一个二维数组 */uint32_t next_num; /* 二维数组中的第一纬度有多少个 */
};

mct_controller_t

也就是mct_controller_t结构体,开启session会拥有一个这个结构体

struct _mct_controller {mct_queue_t   *serv_cmd_q;mct_queue_t   *bus_cmd_q;pthread_mutex_t  serv_msg_q_lock;pthread_mutex_t  server_lock;/* Server result Q and its lock */mct_queue_t   *serv_res_q;pthread_mutex_t  serv_res_q_lock;/* signal variable and its lock */pthread_cond_t serv_res_cond;pthread_mutex_t serv_res_cond_lock;pthread_cond_t mctl_thread_started_cond;pthread_mutex_t mctl_thread_started_mutex;/* 1. Server communicates with Media Controller through signal(servSignal);* 2. Media Controller communicate with Server through Pipe(servFd) */int         serv_fd;int         config_fd;pthread_t   mct_tid;             /* Thread ID of mct main thread */pthread_t   mct_bus_handle_tid;  /* Thread ID of mct bus_handler thread */pthread_cond_t mctl_cond;pthread_mutex_t mctl_mutex;pthread_cond_t mctl_bus_handle_cond;pthread_mutex_t mctl_bus_handle_mutex;mct_thread_state_type bus_thread_state;pthread_mutex_t mctl_state_mutex;pthread_cond_t mctl_state_cond;serv_cmd_q的计数器unsigned int serv_cmd_q_counter;以下结构体也很复杂,在mct_pipline.h里面有定义mct_pipeline_t *pipeline;/* HAL callback */void *event_cb;
};

上面serv_cmd_q变量的消息体,用在server线程中:

typedef struct _mct_serv_msg {这个消息是HAL msg还是Domain Socketmsg如果是socket 则为ds_msg如果是hal,则是hal_msg    mct_serv_msg_type msg_type;union {mct_serv_ds_msg_bundle_t ds_msg;struct v4l2_event hal_msg;} u;
} mct_serv_msg_t;

port

port模块主要的结构体

struct _mct_port {mct_object_t          object;mct_port_caps_t       caps;mct_port_direction_t  direction;相关的port,stream形成的链路,容一个我角色,如都为srcmct_port_t           *peer;相关的port,stream形成的链路,中间伙伴mct_port_t           *internal_peer[MAX_PORT_CONNECTIONS];mct_inter_peer_entity_t  inter_session_peer[MAX_PORT_CONNECTIONS];void                 *port_private;/* virtual functions to be defined by individual ports */执行函数,用于数据流执行函数mct_port_event_func                event_func;mct_port_intra_event_func       intra_event_func;中间连接函数mct_port_int_link_func             int_link;mct_port_ext_link_func             ext_link;mct_port_intra_link_func           intra_link;mct_port_unlink_func               un_link;mct_port_intra_unlink_func         intra_unlink;mct_port_set_caps_func             set_caps;mct_port_check_caps_reserve_func   check_caps_reserve;mct_port_check_caps_unreserve_func check_caps_unreserve;
};typedef struct {uint32_t session_id;uint16_t num_cid_ch;     /* num CIDs from sensor */sensor_src_port_cap_entry_t sensor_cid_ch[SENSOR_CID_CH_MAX];uint8_t num_meta_ch;    /* num of meta channels */sensor_src_port_cap_entry_t meta_ch[MAX_META];uint8_t is_stereo_config;
} sensor_src_port_cap_t;

pipeline

struct _mct_pipeline {mct_module_t            module;mct_bus_t               *bus;mct_controller_t        *controller; //管理pipeline的controller,controller内部有成员指向该pipelinemct_list_t              *modules;   //全局链表的首节点mct_queue_t             *param_queue;session交互的数据格式mct_pipeline_session_data_t session_data;stream交互的数据格式mct_pipeline_session_stream_info_t session_stream;该pipeline拥有的多少条正在执行stream郑,这个是计数器  int8_t                   stream_on_cnt;省略部分//函数指针  此pipe提供的方法mct_pipeline_add_stream_func    add_stream;mct_pipeline_remove_stream_func remove_stream;发送事件函数,一般都是将数据发送到stream上mct_pipeline_event_func         send_event;mct_pipeline_set_bus_func       set_bus;mct_pipeline_get_bus_func       get_bus;mct_pipeline_map_buf_func       map_buf;mct_pipeline_unmap_buf_func     unmap_buf;mct_pipeline_map_parm_func      map_parm;mct_pipeline_unmap_parm_func     unmap_parm;处理server线程的函数指针mct_pipeline_proc_msg_func      process_serv_msg;处理bus线程的函数指针mct_pipeline_proc_msg_func      process_bus_msg;每个module下子设备的线程变量mct_pipeline_thread_data_t      thread_data;
}typedef struct{pthread_t pid;mct_module_t *module;unsigned int session_id;pthread_cond_t cond_v;mct_sync_data_t sync;pthread_mutex_t mutex;unsigned int started_num;unsigned int started_num_success;unsigned int modules_num;
}mct_pipeline_thread_data_t;

消息队列,存储消息

typedef struct _mct_queue {消息头结点mct_list_t   *head;      消息尾结点mct_list_t   *tail;      一共有多少个节点uint32_t length;
} mct_queue_t;

获取strea信息结构体:

typedef struct _mct_pipeline_get_stream_info {mct_pipeline_check_stream_t check_type;uint32_t                    stream_index;cam_stream_type_t           stream_type;uint32_t                    session_index;cam_feature_mask_t          feature_mask;
} mct_pipeline_get_stream_info_t;

Stream

stream总结构体:

struct _mct_stream {/* Stream's parent should be pipeline,* Stream's children should be modules which is arranged from* source module to sink module -* Note: Only Stream's children list can grow into a TREE form */mct_object_t     object;uint32_t streamid;mct_stream_info_t  streaminfo;/** Everything is in one thread context, there is no need* to stuck in State. We shall difinitely NOT consider* asynchronous State transition, otherwise things could* end up with much complexity.** At stream layer, 3 States: LINKED STOP and RUNNING should be* sufficient.*/mct_stream_state_t     state;uint32_t               current_frame_id;void                   *kernel_sof_ptr;uint32_t               hw_sleep_frame_id;mct_stream_bufs_t      buffers;void                   *stream_private;int                    buf_mgr_fd;mct_stream_metadata_t  metadata_stream; /*Could be added to stream private?*/mct_list_t             *frame_num_idx_list;boolean                valid_buffer;/* virtual functions */mct_stream_add_module_func     add_module;mct_stream_remove_module_func  remove_module;mct_stream_insert_module_func  insert_module;mct_stream_configure_func      configure;mct_stream_send_event_func     send_event;mct_stream_link_modules_func   link;mct_stream_unlink_modules_func unlink;mct_stream_map_buf_func        map_buf;mct_stream_unmap_buf_func      unmap_buf;mct_stream_map_parm_func       map_parm;mct_stream_unmap_parm_func     unmap_parm;
};

stream详细info结构体

typedef struct _mct_stream_info_t {unsigned int identity;/* stream type*/cam_stream_type_t stream_type;/* image format */ /* for sensor, */cam_format_t fmt;/* image dimension */ /* for sensor, */cam_dimension_t dim;/* buffer plane information, will be calc based on stream_type, fmt,dim, and padding_info(from stream config). Info including:offset_x, offset_y, stride, scanline, plane offset */cam_stream_buf_plane_info_t buf_planes;/* streaming type */cam_streaming_mode_t streaming_mode;/* burst number of snapshot */int num_burst;/*num of frames generated* only valid when streaming mode = CAM_STREAMING_MODE_BATCH*/cam_stream_user_buf_info_t user_buf_info;/*DS mapped buffer information*/mct_list_t *img_buffer_list;/* Stream buffer parameters */cam_stream_parm_buffer_t parm_buf;cam_pp_feature_config_t pp_config;cam_stream_reproc_config_t reprocess_config;int num_bufs;mct_stream_status_t status;mct_stream_t *stream;/* Buffer params during aspect ratio mismatch */uint32_t resize;cam_dimension_t original_dim;boolean expect_divert;/*TODO: Add more fileds based on requirements*//* Image Stabilization type */cam_is_type_t is_type;uint8_t dis_enable;cam_stream_secure_t is_secure;cam_perf_mode_t perf_mode;
} mct_stream_info_t;
typedef struct {void                 *stream_info;size_t               stream_size;int                   stream_fd;mct_list_t           *img_buf;mct_list_t           *container_buf;pthread_mutex_t       lock_img_buf;
} mct_stream_bufs_t;

bus

struct _mct_bus {unsigned int session_id;bus总线上存储的消息队列mct_queue_t     *bus_queue;bus总线上存储的优先级的消息队列mct_queue_t  *priority_queue;/* Mutex for bus_queue */pthread_mutex_t bus_msg_q_lock;/* Mutex for priority_queue */pthread_mutex_t priority_q_lock;/* Bus signalling constructs */pthread_mutex_t *mct_mutex;pthread_cond_t  *mct_cond;post_msg_to_bus_func post_msg_to_bus;/* SOF-monitor thread signalling constructs */pthread_mutex_t bus_sof_msg_lock;pthread_cond_t  bus_sof_msg_cond;pthread_mutex_t bus_sof_init_lock;pthread_cond_t  bus_sof_init_cond;pthread_t       bus_sof_tid;线程运行状态,1表示内部线程已启动,线程为mct_bus_sof_thread_run函数int             thread_run;uint32_t        prev_sof_id;mct_bus_msg_type_t msg_to_send_metadata;uint32_t        thread_wait_time;
};

bus总线上发送的消息消息结构体

typedef struct _mct_bus_msg {uint32_t sessionid;mct_bus_msg_type_t type;uint32_t size;       此大小是指后面msg指针指向对象大小void *msg;mct_bus_metadata_collection_type_t metadata_collection_type;
} mct_bus_msg_t;

处理bus总线上消息后的返回结构体:

typedef struct _mct_process_ret {这个type表示处理的message是一个sever msg还是bus msg如果是server msg,则SERV_RET_TO_HAL_CMDACK是控制指令,SERV_RET_TO_HAL_NOTIFY缓存映射如果是bus msg则使用SERV_RET_TO_HAL_NOTIFY MCT_PROCESS_RET_BUS_MSGmct_process_ret_type type;union {处理server message后的返回mct_proc_serv_msg_ret serv_msg_ret;处理bus总线message后的返回mct_proc_bus_msg_ret  bus_msg_ret;} u;
} mct_process_ret_t;typedef struct _mct_proc_serv_msg_ret {boolean error;mct_serv_msg_t msg;
} mct_proc_serv_msg_ret;typedef struct _mct_proc_bus_msg_ret {boolean error;mct_bus_msg_type_t msg_type;meta data的缓存buffer indexint metadata_buf_idx;int sof_debug;unsigned int session;unsigned int stream;
} mct_proc_bus_msg_ret;

与sensor相关的结构体

typedef struct {/* Sensor module information for each sensor */mct_list_t                 *sensor_bundle; /* mct_list_t里面data是module_sensor_bundle_info_t,它存储了所有子设备subdev信息 * */void                       *eebin_hdl;   //eeprom驱动层的调用句柄/* Number of sensor bundle information - one per sensor successfully probed */uint8_t                     size;mct_stream_info_t           streaminfo;int32_t                     session_count;/* Two sessions are linked for dual cam support. */boolean                     is_dual_cam;/* STREAM_ON command is issued for both sessions. */boolean                     is_dual_stream_on;/* actual streaming for both sessions */boolean                     is_dual_streaming;pthread_mutex_t             dual_cam_mutex;
} module_sensor_ctrl_t;

sensor下面子设备相关的函数结构体:

typedef struct module_sensor_bundle_info_t {/* info common for module and sensor submodule */sensor_submod_common_info_t    sensor_common_info;/* for intra port communication : initial value -1*/uint32_t                       peer_identity;/* Entity to store subdev name for all imager modules */char sensor_sd_name[SUB_MODULE_MAX][MAX_SUBDEV_SIZE];/* Entity to store information of all subdev interfaces */sensor_submodule_info_t        subdev_info[SUB_MODULE_MAX];/* Entity to store sensor name and index of its sub modules */struct msm_sensor_info_t      *sensor_info;/* Sensor library params */sensor_lib_params_t           *sensor_lib_params;/* chromatix manager */chromatix_manager_type         chromatix_manager;/* eeprom data */format_data_t                 *formatted_data;sensor module下所有子设备的控制函数指针,每个数组对应一个子设备param,其中存放了对驱动层子设备的open、process和close函数,可以与kernl驱动层交互module_sensor_params_t        *module_sensor_params[SUB_MODULE_MAX];/* stream ref count */uint16_t                       ref_count;/* max width of all streams */uint32_t                       max_width;/* max height of all streams */uint32_t                       max_height;/* stream mask of all streams */uint32_t                       stream_mask;/* refcount for non bundle stream on / off */int32_t                        stream_on_count;uint32_t                       last_idx;uint16_t                       num_skip;/* 1 started, 2, done, 3 done no led */sensor_aec_est_state_t         state;uint32_t                       regular_led_trigger;int32_t                        regular_led_af;cam_flash_mode_t               last_flash_request;uint32_t                       stream_thread_wait_time;/* store chromatix pointers to post to bus */mct_bus_msg_sensor_metadata_t    chromatix_metadata;/* store trigger update to post to bus */mct_bus_msg_stats_aec_metadata_t aec_metadata;sensor_eeprom_data_t            *eeprom_data;/* Store sensor_params to post to bus */cam_sensor_params_t            sensor_params;uint32_t                       torch_on;int32_t                        longshot;cam_fps_range_t                fps_info;sensor_frame_ctrl_params_t     frame_ctrl;pthread_mutex_t                mutex;pthread_cond_t                 cond;int32_t                        init_config_done;int32_t                        open_done;int32_t                        res_cfg_done;int32_t                        actuator_cfg_done;int32_t                        parm_pending;/* To be set when set/get parm need to be blocked */int32_t                        block_parm;/* Store HAL version */int32_t                        hal_version;/* Store capture intent */int32_t                        capture_intent;sensor_hal_params_t            hal_params;sensor_flash_params_t          flash_params;/* Sensor Bracketing Feature Specific */sensor_af_bracket_t            af_bracket_params;sensor_bracket_params_t        flash_bracket_params;sensor_capture_control_t       cap_control;/* counter for LED off in burst mode */int16_t                        led_off_count;float                          led_off_gain;uint32_t                       led_off_linecount;uint32_t                       burst_num;uint32_t                       led_on_period;uint32_t                       flash_rer_enable;/**** Flash control info ****/uint32_t                       main_flash_on_frame_skip;uint32_t                       main_flash_off_frame_skip;uint32_t                       torch_on_frame_skip;uint32_t                       torch_off_frame_skip;int8_t                         retry_frame_skip;uint32_t                       capture_pipeline_delay;uint8_t                        partial_flash_frame_skip;int8_t                         batch_idx;uint32_t                       delay_frame_idx;pthread_mutex_t                capture_control_mutex;/**********************/与驱动层的管道端口int32_t                        pfd[2];uint32_t                       isp_frameskip[CAM_STREAM_TYPE_MAX];uint8_t                        is_bayer;uint32_t                       identity[CAM_STREAM_TYPE_MAX];/*This mask is used to execute OIS commands after OIS init is done*/uint16_t                       ois_cmd_queue_mask;/* During fast aec mode, mctl thread will block on this thread */pthread_cond_t                 fast_aec_cond;/* Mutex used for fast aec mode */pthread_mutex_t                fast_aec_mutex;/* number of frames to skip for fast AEC use case */uint16_t                       sensor_num_fast_aec_frame_skip;uint16_t                       fast_aec_wait_count;boolean                        fast_aec_is_running;boolean                        fast_aec_required;uint32_t                       ois_enabled;int32_t                        ois_mode;uint32_t                       max_isp_frame_skip;void *                         external_library[SENSOR_EXTERNAL_LIB_MAX];float                          actuator_sensitivity;cam_stream_size_info_t         stream_size_info;cam_capture_frame_config_t     hal_frame_batch; /*from HAL*/int32_t                        live_connect_fd[2];boolean                        live_connect_thread_started;uint32_t                       is_valid_dualcalib;cam_related_system_calibration_data_t dualcam_tune_data;uint8_t                        subsequent_bundle_stream;uint32_t                       delay_frame_cnt;uint32_t                       ext_pipeline_delay;uint32_t                       cur_scene_mode;float                          digital_gain;void                           *isp_cap;camif_cap_t                    camif_data_fmt;cam_led_calibration_mode_t     led_calibration_mode;uint16_t                       cur_logical_lens_pos;boolean                        sensor_sleeping;boolean                        is_stereo_configuration;struct module_sensor_bundle_info_t*   stereo_peer_s_bundle;
} module_sensor_bundle_info_t;typedef struct {module_sensor_bundle_info_t *s_bundle;会话session iduint32_t                     session_id;    uint32_t                     stream_id;
} sensor_bundle_info_t;typedef struct {void                *sensor_lib_handle;sensor_lib_t        *sensor_lib_ptr;sensor_custom_API_t  sensor_custom_API;
} sensor_lib_params_t;

module_sensor_params_t结构体中的func_tbl函数指针,如下:

typedef struct {/* Open func for sub module1st param -> Address of function table to be filled by sub module2nd param -> Subdev inforeturn status -> success / failure */int32_t (*open)(void **, void *);/* Set param for sub module1st param -> module pointer2nd param -> event type3rd param -> private datareturn status -> success / failure */int32_t (*process)(void *, sensor_submodule_event_type_t, void *);/* close func for sub module1st param -> module pointerreturn status -> success / failure */int32_t (*close)(void *);
} sensor_func_tbl_t;

SENSOR_SUB_MODULE_PROCESS_EVENT宏定义,就会调用上面这个函数指针;
首先,sensor_bundle_info_t里面的类型为module_sensor_params_t,名称为module_sensor_params是一个数组,分别对应sensor下面的每个子设备;而module_sensor_params_t里面有一个函数结构体指针名字为func_tbl,而这个函数指针如何初始化,是依靠下面这个数组写好的,每个子设备的函数指针:

static int32_t (*sub_module_init[SUB_MODULE_MAX])(sensor_func_tbl_t *) = {[SUB_MODULE_SENSOR]       = sensor_sub_module_init,                                                                                                                                                                                                                                    [SUB_MODULE_CHROMATIX]    = chromatix_sub_module_init,[SUB_MODULE_ACTUATOR]     = actuator_sub_module_init,[SUB_MODULE_EEPROM]       = eeprom_sub_module_init,[SUB_MODULE_LED_FLASH]    = led_flash_sub_module_init,[SUB_MODULE_CSIPHY]       = csiphy_sub_module_init,[SUB_MODULE_CSIPHY_3D]    = csiphy_sub_module_init,[SUB_MODULE_CSID]         = csid_sub_module_init,[SUB_MODULE_CSID_3D]      = csid_sub_module_init,[SUB_MODULE_OIS]          = ois_sub_module_init,[SUB_MODULE_EXT]          = external_sub_module_init
};

每个子设备的初始化函数,会返回func_tbl指针;
最后使用SENSOR_SUB_MODULE_PROCESS_EVENT宏定义可以快速调用这个指针;如:

调用s_bundle下面的SUB_MODULE_SENSOR子设备的func_tbl指针的process函数,
传递的参数为SENSOR_GET_SENSOR_FORMAT和output_format,rc是返回值
SENSOR_SUB_MODULE_PROCESS_EVENT(s_bundle, SUB_MODULE_SENSOR,                                                                                                                                                                                                                           SENSOR_GET_SENSOR_FORMAT, &output_format, rc);

创建Sensor module的MCT模块

在mct中,每个module的初始化都写到了一个数组中去了,如下:

每条内容依次是module名字、初始化函数、析构函数以及最后一个模块module
static mct_module_init_name_t modules_list[] = {{"sensor", module_sensor_init,   module_sensor_deinit, NULL},{"iface",  module_iface_init,   module_iface_deinit, NULL},{"isp",    module_isp_init,      module_isp_deinit, NULL},{"stats",  stats_module_init,    stats_module_deinit, NULL},{"pproc",  pproc_module_init,    pproc_module_deinit, NULL},{"imglib", module_imglib_init, module_imglib_deinit, NULL},
};
sensor — sensor 的驱动模块   ——  src模块;
iface — ISP interface模块   —— inter模块;
isp — 主要是ISP的处理,其内部又包含了众多的模块 —— inter模块 ,如本文档主要涉及的bpc、bcc和snr子模块;
stats — 一些统计算法模块,如3A,ASD,AFD,IS,GRRO等数据统计的处理 ¬—— sink模块;
pproc —— post process处理 —— inter模块;
imglib —— 主要是图片的一些后端处理,如HDR等 —— sink模块。

以上数组中每个item的结构体如下:

 * typedef struct _mct_module_init_name
{const char *name;      名称mct_module_init init_mod; 初始化函数指针mct_module_deinit deinit_mod;  析构函数指针mct_module_t *module;   模块结构体,初始化成功后会返回
} mct_module_init_name_t;

由HAL层进入Vendor是通过shim进入的,在HAl中mm_camera_interface.c中会类似于一种反射的形式,通过字符串函数名称mct_shimlayer_process_module_init调用:

int mct_shimlayer_process_module_init(mm_camera_shim_ops_t*shim_ops_tbl)
{mct_module_t *temp = NULL;int32_t enabled_savemem = 0;char savemem[128];char config_node_name[MAX_DEV_NAME_SIZE];char dev_name[MAX_DEV_NAME_SIZE];int rc = 0;struct msm_v4l2_event_data event_data;if (!shim_ops_tbl) {CLOGE(CAM_SHIM_LAYER, "Ops table NULL");return FALSE;}#if defined(LOG_DEBUG)cam_debug_open();#endifpthread_mutex_init(&session_mutex, NULL);//config_node_name 获取为video0 video1 ...if (get_config_node_name(config_node_name) == FALSE) {CLOGE(CAM_SHIM_LAYER, "Failed to get config node name");}snprintf(dev_name, sizeof(dev_name), "/dev/%s", config_node_name);//非阻塞式打开这个虚拟设备config_fd = open(dev_name, O_RDWR | O_NONBLOCK);if (config_fd < 0) {CLOGE(CAM_SHIM_LAYER, "Failed to open config node");}property_get("cameradaemon.SaveMemAtBoot", savemem, "0");enabled_savemem = atoi(savemem);初始化各个sensorif (mct_shimlayer_module_sensor_init() == FALSE) {CLOGE(CAM_SHIM_LAYER, "sensor module init failed");return FALSE;}if (enabled_savemem != 1) {初始化其他各个模块if (mct_shimlayer_module_init() == FALSE) {CLOGE(CAM_SHIM_LAYER, "Module init failed");return FALSE;}}/*Sending IOCTL to inform kernel that daemon is not present */禁止DAEMON模式rc = ioctl(config_fd, MSM_CAM_V4L2_IOCTL_DAEMON_DISABLED, &event_data);if (rc < 0) {CLOGE(CAM_SHIM_LAYER, "Failed to send Daemon disabled IOCTL to kernel");}//配置函数指针,返回给hal使用shim_ops_tbl->mm_camera_shim_open_session = mct_shimlayer_start_session;shim_ops_tbl->mm_camera_shim_close_session = mct_shimlayer_stop_session;shim_ops_tbl->mm_camera_shim_send_cmd = mct_shimlayer_process_event;return TRUE;
}
初始化sensor module
static boolean mct_shimlayer_module_sensor_init(void)
{mct_module_t *temp = NULL;CLOGH(CAM_SHIM_LAYER, "Sensor module init");if( NULL == modules_list[0].init_mod)return FALSE;调用上面数组中配置的初始化函数,并返回module结构体temp = modules_list[0].init_mod(modules_list[0].name);if (temp) {modules_list[0].module = temp;把sensor module的结构体添加到全局节点modules链表中去if ((modules = mct_list_append(modules, temp, NULL, NULL)) == NULL) {创建失败,释放sensor模块相关结构体if (modules) {modules_list[0].deinit_mod(temp);modules_list[0].module = NULL;return FALSE;}}}CLOGH(CAM_SHIM_LAYER, "Sensor module init done");return TRUE;
}

mct基础模块不能独立存在,一般都是其他模块用它来创建,比如camera sensor模块创建一个名为sensor的mct模块,那这个模块就是sensor模块;好的,就用这个为例:

----module_sensor.c
mct_module_t *module_sensor_init(const char *name)
{....mct_module_t s_module = mct_module_create("sensor");module_ctrl = malloc(sizeof(module_sensor_ctrl_t));s_module->module_private = (void *)module_ctrl;/* sensor module doesn't have sink port */module_sensor_ctrl_t* s_module->numsinkports = 0;就是创建一个eebin_hdl,赋值给module_ctrlrc = eebin_interface_init(&module_ctrl->eebin_hdl);//查找驱动kernel的eeprom设备,返回其标识rc = eebin_interface_control(module_ctrl->eebin_hdl, &bin_ctl);/* module_sensor_probe_sensors */ret = sensor_init_probe(module_ctrl);/* 查找所有的子设备actuator, etc with sensor */ret = module_sensor_find_other_subdev(module_ctrl);以下mct_list_traverse会遍历sensor_bundle中所有的子设备,并以此调用module_sensors_subinit方法来初始化所有子设备ret = mct_list_traverse(module_ctrl->sensor_bundle, module_sensors_subinit,NULL);....创建port基于CID信息,port_sensor_create是port_sensor.c的函数ret = mct_list_traverse(module_ctrl->sensor_bundle, port_sensor_create,                                                                                                                                                                                                                s_module);if (ret == FALSE) {SERR("failed");goto ERROR1;}return s_module;
}----mct_module.c
mct_module_t* mct_module_create(const char *name)
{mct_module_t *new_module;new_module = malloc(sizeof(mct_module_t));if (!new_module) {/*print error code here strerror(errno)*/return FALSE;}memset(new_module, 0, sizeof(mct_module_t));初始化mct_obj的lock互斥量,暂不清楚使用pthread_mutex_init(MCT_OBJECT_GET_LOCK(new_module), NULL);初始化type_list_lock互斥量pthread_mutex_init(&new_module->type_list_lock, NULL);MCT_OBJECT_CAST就是强者把new_module转换为变量使用,将其object的name设置mct_object_set_name(MCT_OBJECT_CAST(new_module), name);设置其set_mod、query_mod、start_session和stop_session等虚函数mct_module_set_set_mod_func(new_module, mct_module_set_mod_default);mct_module_set_query_mod_func(new_module, mct_module_query_mod_default);//mct_module_set_request_port_func(new_module,//  mct_module_request_port_default);mct_module_set_start_session_func(new_module,mct_module_start_session_default);mct_module_set_stop_session_func(new_module,mct_module_stop_session_default);return new_module;
}

sensor创建port

在上面module_sensor_init函数最几句代码执行mct_list_traverse会遍历所有bundle信息,然后执行port_sensor_create函数:

boolean port_sensor_create(void *data, void *user_data)
{boolean                      ret = TRUE;int32_t                      rc = SENSOR_SUCCESS;mct_port_t                  *s_port = NULL;module_sensor_bundle_info_t *s_bundle = (module_sensor_bundle_info_t *)data;sensor_lib_params_t         *sensor_lib_params = NULL;mct_module_t                *s_module = (mct_module_t *)user_data;module_sensor_ctrl_t        *module_ctrl = NULL;int32_t                      i = 0, j = 0;char                         port_name[32];module_sensor_params_t      *module_sensor_params = NULL;module_sensor_params_t      *module_right_sensor_params = NULL;sensor_stream_info_array_t  *sensor_stream_info_array = NULL;sensor_stream_info_array_t  *right_sensor_stream_info_array = NULL;sensor_src_port_cap_t       *sensor_src_port_cap = NULL;module_sensor_params_t      *csid_module_params = NULL;uint32_t                     csid_version = 0;uint8_t                      num_meta_ch = 0;uint32_t                     pix_fmt_fourcc = 0;获取sensor下子设备的相关参数,返回参数有open、process和close                                                                                                                                                                                                                    module_sensor_params = s_bundle->module_sensor_params[SUB_MODULE_SENSOR];csid_module_params = s_bundle->module_sensor_params[SUB_MODULE_CSID];调用csid的子设备的open函数,open 会打开/dev/下的子设备,将kernel返回的fd保存在csid自己的结构体中,之后就可以通过这个fd与驱动层访问了rc = csid_module_params->func_tbl.open(&csid_module_params->sub_module_private,&s_bundle->subdev_info[SUB_MODULE_CSID]);if (rc < 0) {SERR("failed");return FALSE;}获取csid的版本号,根据命令码CSID_GET_VERSIONrc = csid_module_params->func_tbl.process(csid_module_params->sub_module_private,CSID_GET_VERSION, &csid_version);ioctl传递关闭csid指令csid_module_params->func_tbl.close(csid_module_params->sub_module_private);module_ctrl = (module_sensor_ctrl_t *)s_module->module_private;sensor_lib_params = s_bundle->sensor_lib_params;获取sensor下流stream信息,读取到sensor_stream_info_array数组中rc = module_sensor_params->func_tbl.process(s_bundle->sensor_lib_params,SENSOR_GET_SENSOR_PORT_INFO, &sensor_stream_info_array);感觉像是另一个s_bundle,就是子设备都是成对的if (NULL != s_bundle->stereo_peer_s_bundle) {获取右边的sensor parammodule_right_sensor_params =s_bundle->stereo_peer_s_bundle->module_sensor_params[SUB_MODULE_SENSOR];将右边的stream信息读取到right_sensor_stream_info_array数组rc = module_right_sensor_params->func_tbl.process(s_bundle->stereo_peer_s_bundle->sensor_lib_params,SENSOR_GET_SENSOR_PORT_INFO, &right_sensor_stream_info_array);遍历sensor下的stream信息for (j = 0; j < sensor_stream_info_array->size; j++) {如果第j条流stream的size大于最大值,错误if (SENSOR_CID_CH_MAX <sensor_stream_info_array->sensor_stream_info[j].vc_cfg_size) {SERR("vc_cfg_size out of range (%d) ",(int) sensor_stream_info_array->sensor_stream_info[j].vc_cfg_size);goto ERROR1;}sensorX,X是index,作为port的名称snprintf(port_name, sizeof(port_name), "%s%d",s_bundle->sensor_info->sensor_name, j);创建ports_port = mct_port_create(port_name);sensor_src_port_cap = malloc(sizeof(sensor_src_port_cap_t));....省略为s_port赋值的过程.....s_port->direction = MCT_PORT_SRC;s_port->check_caps_reserve = port_sensor_caps_reserve;s_port->check_caps_unreserve = port_sensor_caps_unreserve;s_port->ext_link = port_sensor_ext_link_func;s_port->un_link = port_sensor_unlink_func;s_port->event_func = port_sensor_port_process_event;s_port->intra_event_func = port_sensor_port_process_event;.......  将s_port作为s_module的子对象,并且根据direction将port加入到s_module的的srcports或sinkport链表中  ret = mct_module_add_port(s_module, s_port);
}

这样就把mct_module的port加入进去了,因为sensor module是src的,所以它只有source port

sensor module初始化总结

经过module_sensor_init函数会进入sensor module模块内部,

  1. 首先会创建mct_module_t结构体,再次创建sensor模块的module_sensor_ctrl_t结构体,前者是mct所有module的共性部分结构体,后者每个module不同的结构体,他们之间也有引用关系;
  2. 在sensor中首先会open其驱动层/dev/video,然后找到其下面的sub_dev如actuator、etc等等,并将他们的信息写入到module_sensor_ctrl_t结构体中
  3. 然后会使用mct_list_traverse函数多次遍历module_sensor_ctrl_t结构体中的子设备,执行其初始化、创建管理器等
  4. mct_module根据自己内部的子设备信息中的stream,创建port,然后加入到mct_module的srcport里面去
  5. 最后将mct_module_t结构体写入到链表modules中去,其类型为mct_list_t,链表中的data为mct_module_t类型

记住在,相对于各个module模块的全局链表类型为mct_list_t,名字为modules,链表中存储的数据类型为mct_module_t,这是一个全局的

上图是初始化的逻辑关系图,各个逻辑模块最终都会用数据结构体整合在一起;外层各个module会用mct_list组成list保存,每个module都是一个mct_module结构体,这个mct_module内部的module_private成员是具体模块的结构体,如sensor module就是一个module_sensor_ctrl_t类型,赋值在module_private成员上,而module_sensor_ctrl_t作为sensor module的类型,其下面会有许多子设备,这些子设备存储在sensor_bundle成员下面,而最终又会创建许多port模块,这些port模块作为src,赋值在module_sensor_ctrl_t的子对象里面


start_session业务

其他的module初始化暂部分性,我们进行下一步,创建好module后,还需要打通与其的连接,MCT通过session来访问,入口函数:

cam_status_t mct_shimlayer_start_session(int session,mm_camera_shim_event_handler_func event_cb)
{int32_t enabled_savemem;char savemem[128];cam_status_t ret = CAM_STATUS_FAILED;
.....if (enabled_savemem == 1) {//如果没有初始化  这里就要初始化if (mct_shimlayer_module_init() == FALSE) {pthread_mutex_unlock(&session_mutex);return CAM_STATUS_FAILED;}}session是打开dev/video后的session  config_fd是打开dev/video后的文件描述符modules是mct链表的首节点,每个node节点对应一个硬件模块,如sensor isp等ret = mct_controller_new(modules, session, config_fd, event_cb);....
}

上面直观重要的就是mct_controller_new函数,跟进去看看:

cam_status_t mct_controller_new(mct_list_t *mods,unsigned int session_idx, int serv_fd, void *event_cb)
{以下结构体结构体文章上面有,是_mct_controller类型mct_controller_t *mct = NULL;mct_controller_t就是_mct_controller类型,在此文件头文件里面定义mct = (mct_controller_t *)malloc(sizeof(mct_controller_t));创建pipeline,其内部还要创建mct_queue队列和mct_bus总线mct->pipeline = mct_pipeline_new(session_idx, mct);为pipeline的modules赋值mods,是全局的moduels链表mct->pipeline->modules = mods;启动会话ret_type = mct_pipeline_start_session(mct->pipeline);//mct_queue_new是一个宏定义,就是创建一个mct_queue_t结构体mct->serv_cmd_q = mct_queue_new;mct->serv_cmd_q_counter = 0;记录来自hal的回调event事件mct->event_cb = event_cb;定义bus线程为idle状态mct->bus_thread_state = MCT_THREAD_STATE_IDLE;初始化mct_queue_t结构体,serv_cmd_q是一个mct_queue_t类型mct_queue_init(mct->serv_cmd_q);mct->serv_res_q = mct_queue_new;mct_queue_init(mct->serv_res_q);记录/dev/video的文件句柄mct->config_fd = serv_fd;创建mct_controller_thread_run线程 -- mctif (pthread_create(&tid, NULL, mct_controller_thread_run, mct)) {pthread_mutex_unlock(&mct->mctl_thread_started_mutex);goto main_thread_error;}pthread_setname_np(tid, "CAM_MctServ");等待上面线程正常执行后继续执行pthread_cond_wait(&mct->mctl_thread_started_cond,&mct->mctl_thread_started_mutex);pthread_mutex_unlock(&mct->mctl_thread_started_mutex);mct->mct_tid = tid;创建mct_bus_handler_thread_run线程 -- busif (pthread_create(&bus_hdl_tid, NULL, mct_bus_handler_thread_run, mct)) {pthread_mutex_unlock(&mct->mctl_bus_handle_mutex);goto bus_handle_thread_error;}pthread_setname_np(bus_hdl_tid, "CAM_MctBus");pthread_mutex_unlock(&mct->mctl_bus_handle_mutex);mct->mct_bus_handle_tid = bus_hdl_tid;mct->pipeline->bus->mct_mutex = &mct->mctl_bus_handle_mutex;mct->pipeline->bus->mct_cond  = &mct->mctl_bus_handle_cond;mcts又是一个全局的变量,也是一个链表,将mct加入到这个链表中if (!(mcts = mct_list_append(mcts, mct, NULL, NULL))) {goto all_error;}return CAM_STATUS_SUCCESS;
}

小结

开启会话会创建多个结构体,其中以mct_controller_t为主以及pipeline和bus等,然后在pipeline启动会话session,再创建两个线程mct_controller_thread_run和mct_bus_handler_thread_run,最后,把此次会话创建的mct_controller_t结构体加入mcts链表中,它也是一个mct_list_t类型,只不过其中元素类型为mct_controller_t,记住目前为止,已经有两个全局链表了,一个是modules,一个是mcts,这里先分析创建的pipeline,在分析后面两个线程


pipeline模块

pipeline模块由 mct_pipeline_new 函数创建,如下:

mct_pipeline_t* mct_pipeline_new (unsigned int session_idx,mct_controller_t *pController)
{mct_pipeline_t *pipeline;pipeline = malloc(sizeof(mct_pipeline_t));pipeline->session = session_idx;与外层的mct_controller_t相互引用pipeline->controller = pController;以下宏定义就是强制拿去pipeline内部的obj成员变量mct_object_t *obj = MCT_OBJECT_CAST(pipeline);obj->children = NULL;obj->childrennum = 0;创建mct_queue_t数据结构体pipeline->super_param_queue = (mct_queue_t *)mct_queue_new;初始化queue内部各成员变量mct_queue_init(pipeline->super_param_queue);创建bus结构体pipeline->bus = mct_bus_create(session_idx);pipeline->sleep_duration = MCT_PIPELINE_SLEEP_DURATION;给pipeline内部函数指针变量赋值pipeline->map_buf   = mct_pipeline_map_buf;pipeline->unmap_buf = mct_pipeline_unmap_buf;pipeline->map_parm   = mct_pipeline_map_parm;pipeline->unmap_parm = mct_pipeline_unmap_parm;/* For case SERV_MSG_SET,SERV_MSG_GET, SERV_MSG_STREAMON, SERV_MSG_STREAMOFF,SERV_MSG_QUERY,SERV_MSG_CLOSE_SESSION */pipeline->process_serv_msg= mct_pipeline_process_serv_msg;pipeline->process_bus_msg = mct_pipeline_process_bus_msg;pipeline->add_stream    = mct_pipeline_add_stream;pipeline->remove_stream = mct_pipeline_remove_stream;pipeline->send_event    = mct_pipeline_send_event;pipeline->set_bus       = mct_pipeline_set_bus;pipeline->get_bus       = mct_pipeline_get_bus;pipeline->hal_version   = CAM_HAL_V1;return pipeline;
}

bus模块

上面这块代码很简单,主要是分配内存,然后赋值,里面相对比较关键的是又创建了一个bus结构体,文章前面有这个结构体类型展示,mct_bus_create:

mct_bus_t *mct_bus_create(unsigned int session)
{mct_bus_t *new_bus;new_bus = malloc(sizeof(mct_bus_t));memset(new_bus, 0 , sizeof(mct_bus_t));pthread_mutex_init(&new_bus->bus_msg_q_lock, NULL);pthread_mutex_init(&new_bus->priority_q_lock, NULL);pthread_mutex_init(&new_bus->bus_sof_init_lock, NULL);pthread_cond_init(&new_bus->bus_sof_init_cond, NULL);new_bus->bus_queue = mct_queue_new;if (!new_bus->bus_queue) {pthread_mutex_destroy(&new_bus->bus_msg_q_lock);goto busmsgq_error;}mct_queue_init(new_bus->bus_queue);new_bus->priority_queue = mct_queue_new;if (!new_bus->priority_queue) {pthread_mutex_destroy(&new_bus->priority_q_lock);goto busmsgq_error;}mct_queue_init(new_bus->priority_queue);赋值函数指针mct_bus_post_msg,其字面意思就是将消息推送到bus总线上去new_bus->post_msg_to_bus = mct_bus_post_msg;new_bus->session_id = session;return new_bus;
}

消息推送到bus总线
这里,你可以把bus理解为总线,总线就是数据通信中的主要道路,所有的信息msg最终都会把消息传递到bus总线,再由总线发送到其他地方,以下代码相对长,但是比较简单;

static boolean mct_bus_post_msg(mct_bus_t *bus, mct_bus_msg_t *bus_msg)
{mct_bus_msg_t *local_msg;boolean post_msg = FALSE;mct_bus_msg_isp_sof_t *isp_sof_bus_msg = NULL;unsigned int payload_size;if (!bus || !bus_msg) {CLOGE(CAM_MCT_MODULE, "NULL ptr detected: bus = [%p], bus_msg = [%p]",bus, bus_msg);goto error_2;}//如果bus总线上存储消息队列长度超过1000个if (bus->bus_queue->length > MAX_MCT_BUS_QUEUE_LENGTH) {pthread_mutex_lock(&bus->bus_msg_q_lock);//flush所有存储的消息mct_bus_queue_flush(bus);CLOGI(CAM_MCT_MODULE,"Discarded the bus msgs that got stagnated in the queue");pthread_mutex_unlock(&bus->bus_msg_q_lock);return TRUE;}//消息msg的type无效if (bus_msg->type >= MCT_BUS_MSG_MAX) {CLOGI(CAM_MCT_MODULE, "bus_msg type %d is not valid", bus_msg->type);goto error_2;}payload_size = bus_msg->size;//到这儿,说明此次消息是一个有效的消息switch (bus_msg->type) {case MCT_BUS_MSG_ISP_SOF:post_msg = TRUE;if (bus->thread_run == 1) {pthread_mutex_lock(&bus->bus_sof_msg_lock);pthread_cond_signal(&bus->bus_sof_msg_cond);pthread_mutex_unlock(&bus->bus_sof_msg_lock);}isp_sof_bus_msg = bus_msg->msg;CLOGD(CAM_MCT_MODULE,"Posting SOF for frame ID %d", isp_sof_bus_msg->frame_id);break;//error错误,清楚所有的消息case MCT_BUS_MSG_SEND_HW_ERROR:post_msg = TRUE;pthread_mutex_lock(&bus->bus_msg_q_lock);mct_bus_queue_flush(bus);pthread_mutex_unlock(&bus->bus_msg_q_lock);break;//sensor正在启动重case MCT_BUS_MSG_SENSOR_STARTING:bus->thread_wait_time = *((uint32_t *)bus_msg->msg);//启动check线程start_sof_check_thread(bus);return TRUE;break;//sensor停止中,结束check线程case MCT_BUS_MSG_SENSOR_STOPPING:stop_sof_check_thread(bus);return TRUE;break;case MCT_BUS_MSG_ERROR_MESSAGE:case MCT_BUS_MSG_NOTIFY_KERNEL:case MCT_BUS_MSG_CONTROL_REQUEST_FRAME:case MCT_BUS_MSG_EZTUNE_JPEG:case MCT_BUS_MSG_EZTUNE_RAW:case MCT_BUS_MSG_DELAY_SUPER_PARAM:case MCT_BUS_MSG_FRAME_SKIP:case MCT_BUS_MSG_CAC_STAGE_DONE:case MCT_BUS_MSG_ISP_RD_DONE:post_msg = TRUE;break;default:break;}local_msg = malloc(sizeof(mct_bus_msg_t));if (!local_msg) {CLOGE(CAM_MCT_MODULE, "Can't allocate memory");goto error_2;}//将传递进来的msg拷贝到本地消息local_msg->sessionid = bus_msg->sessionid;local_msg->type = bus_msg->type;local_msg->size = bus_msg->size;
//payload_size指后面msg指针指向对象大小if (payload_size) {local_msg->msg = malloc(payload_size);if (!local_msg->msg) {CLOGE(CAM_MCT_MODULE, "Can't allocate memory");goto error_1;}memcpy(local_msg->msg, bus_msg->msg, payload_size);} else {local_msg->msg = NULL;}post_msg为true,说明有消息,需要将消息加入到bus总线的queue中,这里加入到priority_queue成员中if (post_msg) {pthread_mutex_lock(&bus->priority_q_lock);入队queuemct_queue_push_tail(bus->priority_queue, local_msg);pthread_mutex_unlock(&bus->priority_q_lock);pthread_mutex_lock(bus->mct_mutex);pthread_cond_signal(bus->mct_cond);pthread_mutex_unlock(bus->mct_mutex);}else {/*Store bus messages in bus_msg queueand dequeue during next SOF. */pthread_mutex_lock(&bus->bus_msg_q_lock);mct_queue_push_tail(bus->bus_queue, local_msg);pthread_mutex_unlock(&bus->bus_msg_q_lock);}return TRUE;
}

此函数的目的就是把mct_bus_msg_t添加到mct_bus_t的两个消息队列queue上,一个priority_queue和一个bus_queue;并且此函数在收到类型MCT_BUS_MSG_SENSOR_STARTING类型会启动一个check函数,看看这个check函数:

static void start_sof_check_thread(mct_bus_t *bus)
{int rc = 0;if (!bus) {CLOGE(CAM_MCT_MODULE, "NULL bus ptr");return;}if (bus->thread_run == 1)return;....pthread_mutex_init(&bus->bus_sof_msg_lock, NULL);pthread_cond_init(&bus->bus_sof_msg_cond, NULL);pthread_mutex_lock(&bus->bus_sof_init_lock);//开启mct_bus_sof_thread_run线程                                                                                                                                                                                                                                                 rc = pthread_create(&bus->bus_sof_tid, NULL, mct_bus_sof_thread_run, bus);if(!rc) {pthread_setname_np(bus->bus_sof_tid, "CAM_sof_timer");pthread_cond_wait(&bus->bus_sof_init_cond, &bus->bus_sof_init_lock);}pthread_mutex_unlock(&bus->bus_sof_init_lock);
}

就是启动一个新线程mct_bus_sof_thread_run:

static void* mct_bus_sof_thread_run(void *data)
{mct_bus_t *bus = (mct_bus_t *)data;设置一个超时时间signed long long timeout =(((signed long long)(bus->thread_wait_time)) * MCT_BUS_NANOSECOND_SCALER);int ret;
线程启动标志bus->thread_run = 1;while(bus->thread_run) {等待超时时间的二分之一ret = mct_bus_timeout_wait(&bus->bus_sof_msg_cond,&bus->bus_sof_msg_lock, timeout/2);if(bus->thread_run) {超时原因导致if ((ret == ETIMEDOUT) && (debug_data == 0)) {enable = 1;debug_data = 1;mct_bus_msg_t bus_msg;bus_msg.type = MCT_BUS_MSG_NOTIFY_KERNEL;bus_msg.size = sizeof(int);bus_msg.msg = (void *)&enable;bus_msg.sessionid = bus->session_id;发送一个enable为1的消息到bus总线上,这个消息会发送到bus->post_msg_to_bus(bus, &bus_msg);} else if ((ret == ETIMEDOUT) && (debug_data == 1)) {,.....break;} else if (debug_data == 1) {enable = 0;debug_data = 0;CLOGE(CAM_MCT_MODULE, "Session %d: Hinting SOF freeze is recover.",bus->session_id);mct_bus_msg_t bus_msg;bus_msg.type = MCT_BUS_MSG_NOTIFY_KERNEL;bus_msg.size = sizeof(int);bus_msg.msg = (void *)&enable;bus_msg.sessionid = bus->session_id;bus->post_msg_to_bus(bus, &bus_msg);}} else {CLOGI(CAM_MCT_MODULE, "Closing SOF tracker thread");break;}
}
线程结束,会清除掉bus内queue的所有消息if (bus->thread_run == 1) {/*Things went wrong*/mct_bus_msg_t bus_msg;bus_msg.type = MCT_BUS_MSG_SEND_HW_ERROR;bus_msg.size = 0;bus_msg.sessionid = bus->session_id;bus->post_msg_to_bus(bus, &bus_msg);}return NULL;
}

bus小结

首先,会创建mct_bus_t结构体,结构体中有两个队列mct_queue_t成员,其队列中存储的主要类型是mct_bus_msg_t

其次,bus模块有个关键函数mct_bus_post_msg,它会将外部的消息根据type类型push到mct_bus_t的bus_queue和priority_queue队列中

最后,在mct_bus_post_msg函数中,type为MCT_BUS_MSG_SENSOR_STARTING会启动一个check线程,这个线程主要设置一个超时时间,周期性的唤醒线程,然后发送MCT_BUS_MSG_NOTIFY_KERNEL类型消息,将消息post到priority_queue队列中

pipeline启动session

回到session启动函数中的mct_controller_new中,创建完pipeline后,会调用mct_pipeline_start_session启动session

cam_status_t mct_pipeline_start_session(mct_pipeline_t *pipeline)
{boolean rc;int ret;struct timespec timeToWait;.....pipeline->thread_data.started_num = 0;pipeline->thread_data.modules_num = 0;pipeline->thread_data.started_num_success = 0;modules是全局modules链表,里面存放了sensor、isp各个module,mct_list_traverse会遍历所有node然后执行mct_pipeline_get_module_num,计算一共有多少个modulerc = mct_list_traverse(pipeline->modules, mct_pipeline_get_module_num,pipeline);遍历每个module,并其执行mct_pipeline_modules_start,这个函数会开启一个线程,打通与kernel层交互,使用管道通信,发现sensor模块是这样的rc &= mct_list_traverse(pipeline->modules, mct_pipeline_modules_start,pipeline);rc = mct_util_get_timeout(MCT_THREAD_TIMEOUT, &timeToWait);........同上,遍历module,执行mct_pipeline_get_session_data方法,第三个是传递的参数rc &= mct_list_traverse(pipeline->modules, mct_pipeline_get_session_data,pipeline);........pipeline->session_data.set_session_mask |= SESSION_DATA_SUPERSET;同上rc &= mct_list_traverse(pipeline->modules, mct_pipeline_set_session_data,pipeline);pipeline->session_data.set_session_mask = 0;将pipeline的session状态设置为启动STARTINGpipeline->session_stream.state = MCT_ST_STATE_STARTING;同时也为这个session活动添加一个stream流信息mct_pipeline_start_stream_internal(pipeline);if (TRUE == rc)return CAM_STATUS_SUCCESS;elsereturn CAM_STATUS_FAILED;
}

如上函数,mct_list_traverse是一个很重要的函数,他会遍历第一个参数中的所有节点node,然后将执行第二个参数,第二个参数是函数指针,最后一个是第二个函数指针需要的参数;所以上面函数重点就是几个mct_list_traverse传递的函数指针是啥意思:
最后,不要遗漏函数后面几行代码mct_pipeline_start_stream_internal,启动stream的函数,里面涉及了stream以及绑定逻辑

第一个mct_pipeline_get_module_num

static boolean mct_pipeline_get_module_num(void *data1 __unused, void *data2)
{mct_pipeline_t *pipeline = (mct_pipeline_t *)data2;pipeline->thread_data.modules_num++;return TRUE;
}

它就是计算一共有多少个module,并记录在pipeline的thread_data成员中的modules_num去

第二个mct_pipeline_modules_start

看名字也就知道,会对各个module执行启动操作,至于启动做什么就要看看以下代码了

static boolean mct_pipeline_modules_start(void *data1, void *data2)
{int rc = 0;pthread_attr_t attr;char thread_name[20];mct_pipeline_t *pipeline = (mct_pipeline_t *)data2;这个thread_data只有一个,但是data1会有多个,也就是有多个module赋值到一个thread_datamct_pipeline_thread_data_t *thread_data = &(pipeline->thread_data);thread_data->module = (mct_module_t *)data1;thread_data->session_id = pipeline->session;为每个module创建一个线程,线程主体执行函数是mct_pipeline_start_session_threadrc = pthread_create(&pipeline->thread_data.pid, &attr,&mct_pipeline_start_session_thread, (void *)thread_data);snprintf(thread_name, sizeof(thread_name), "CAM_start%s",MCT_MODULE_NAME(thread_data->module));if(!rc) {pthread_setname_np(pipeline->thread_data.pid,thread_name);必须要等到子线程执行完成后才能进行下一个module的startpthread_cond_wait(&thread_data->cond_v, &thread_data->mutex);}pthread_mutex_unlock(&thread_data->mutex);return TRUE;
}

这里有一个疑问,thread_data作为pipeline的内部成员,只有一个,而mct_pipeline_modules_start函数因为遍历多个module所以会执行多次,所以thread_data就会被赋值多次,为啥要赋值多次呢?并且这个thread_data要传递到下个线程中去;重点看看mct_pipeline_start_session_thread函数:

static void* mct_pipeline_start_session_thread(void *data)
{mct_pipeline_thread_data_t *thread_data = (mct_pipeline_thread_data_t*)data;mct_module_t *module = thread_data->module;unsigned int session_id = thread_data->session_id;boolean rc = FALSE;....pthread_mutex_lock(&thread_data->mutex);释放信号,上一个函数可以继续往下执行了,因为module和session都已经读取了pthread_cond_signal(&thread_data->cond_v);pthread_mutex_unlock(&thread_data->mutex);如果module的start_session方法不为空if (module->start_session) {CLOGI(CAM_MCT_MODULE, "Calling start_session on Module %s",MCT_MODULE_NAME(module));执行start_session方法,启动会话rc = module->start_session(module, session_id);CLOGI(CAM_MCT_MODULE, "Module %s start_session rc = %d",MCT_MODULE_NAME(module), rc);}pthread_mutex_lock(&thread_data->mutex);成功启动,为线程成功启动的加1thread_data->started_num++;if (rc == TRUE)thread_data->started_num_success++;如果线程启动总数量等于总的module数量,那么释放notify信号if(thread_data->started_num == thread_data->modules_num)pthread_cond_signal(&thread_data->cond_v);pthread_mutex_unlock(&thread_data->mutex);ATRACE_END();CLOGI(CAM_MCT_MODULE, "X %s" , MCT_MODULE_NAME(module));return NULL;
}

这里也很简单,主要就是启动module的start_session方法;这里就解决了上面的疑惑了,当前线程执行前几行代码会马上读取module和session id,然后就释放cond_v信号量,通知上一个函数可以继续执行了,这样就算下一个module执行而来,就算对thread_data重新赋值也没有影响

真正的start_session

到这里,我们发现start_session经过一番折腾,又回到了自己的module模块下,执行器start_session方法,每个module的开启session都不一样,这里我们就只看sensor module了,sensor module在初始化的时候对start_session函数指针赋值为s_module->start_session = module_sensor_start_session,所以:

static boolean module_sensor_start_session(mct_module_t *module, uint32_t sessionid)
{module_sensor_ctrl_t        *module_ctrl = NULL;mct_list_t                  *s_list = NULL;module_sensor_bundle_info_t *s_bundle = NULL;boolean                     ret = TRUE;SHIGH("sessionid %d", sessionid);RETURN_ON_NULL(module);module_ctrl = (module_sensor_ctrl_t *)module->module_private;RETURN_ON_NULL(module_ctrl);ATRACE_BEGIN(PROF_SENSOR_START_SESSION);session id通过session找到kernel驱动层对应的虚拟设备信息 s_list = mct_list_find_custom(module_ctrl->sensor_bundle, &sessionid,sensor_util_find_bundle);RETURN_ON_NULL(s_list);s_bundle = (module_sensor_bundle_info_t *)s_list->data;RETURN_ON_NULL(s_bundle);/* initialize the "torch on" flag to 0 */s_bundle->torch_on = 0;s_bundle->longshot = 0;为这个虚拟设备创建一个线程,一直轮询通过管道读取里面的数据ret = sensor_thread_create(s_bundle);if (ret == FALSE) {SERR("failed to create sensor thread");goto ERROR;}以下双通道都关闭,默认单通道module_ctrl->is_dual_cam = FALSE;module_ctrl->is_dual_stream_on = FALSE;module_ctrl->is_dual_streaming = FALSE;初始化这个session、包括上电、配置sensor等ret = module_sensor_init_session(s_bundle, module_ctrl->eebin_hdl);if (ret == FALSE) {SERR("failed");goto ERROR;}如果是双通道模式就上电if (TRUE == s_bundle->is_stereo_configuration &&s_bundle->stereo_peer_s_bundle != NULL) {SERR("Powering up peer stereo sensor. ");ret = module_sensor_init_session(s_bundle->stereo_peer_s_bundle,module_ctrl->eebin_hdl);if (ret == FALSE) {SERR("failed");goto ERROR;}}SHIGH("SUCCESS");ATRACE_END();return TRUE;
}

sensor_thread_create函数就不进去看了,他就是创建一个线程sensor_thread_func,直接查看这个进程函数是干什么的?

参数data是在sensor_thread_create函数中组装的变量,主要包含与驱动层的通信的管道端口
void* sensor_thread_func(void *data)
{sensor_thread_t *thread = (sensor_thread_t*)data;int32_t readfd, writefd;pthread_mutex_lock(&thread->mutex);设置为true,表示线程开始执行了thread->is_thread_started = TRUE;读取管道readfd = thread->readfd;writefd = thread->writefd;pthread_cond_signal(&thread->cond);pthread_mutex_unlock(&thread->mutex);struct pollfd pollfds;int32_t num_of_fds = 1;boolean thread_exit = FALSE;int32_t ready = 0;设置管道信息以及感兴趣的时间pollfds.fd = readfd;pollfds.events = POLLIN | POLLPRI;cancel_autofocus = FALSE;这个轮询读取的数据来源于哪里?猜测1:管道fd属于s_bundle下的成员,而bundle与自身相关,猜测来源于kernel驱动猜测2:在sensor module下有很多源代码往这个管道写入了数据,如结束session、module_sensor_update_af_bracket_entry等此类型的更多是type为offload类型,函数重载 while(!thread_exit){轮询管道ready = poll(&pollfds, (nfds_t)num_of_fds, -1);if(ready > 0){  有事件正在发生if(pollfds.revents & (POLLIN | POLLPRI)){ssize_t nread = 0;sensor_thread_msg_t msg; 读取管道消息nread = read(pollfds.fd, &msg, sizeof(sensor_thread_msg_t));if(nread < 0) {SERR("Unable to read the message");}如果msg中有停止的信号,结束线程if(msg.stop_thread) {break;}sensor_process_thread_message(&msg);}}else{if (errno != EINTR) {SERR("Unable to ple exiting the thread");break;}}}close(readfd);close(writefd);return NULL;
}void sensor_process_thread_message(sensor_thread_msg_t *msg)
{mct_bus_msg_t               bus_msg;mct_bus_msg_af_status_t     af_msg;enum sensor_af_t            status;int32_t                     i = 0;ssize_t                     ret = 0;cam_focus_distances_info_t  fdistance;SLOW("Processing Pipe message %d", msg->msgtype);long long start __attribute__((unused)) = sensor_current_timestamp();switch(msg->msgtype){消息类型为设置自动对焦case SET_AUTOFOCUS: {status = SENSOR_AF_NOT_FOCUSSED;while  (i < 20) {获取sensor自动对焦状态,最多尝试20次ret = ioctl(msg->fd, VIDIOC_MSM_SENSOR_GET_AF_STATUS, &status);if (ret < 0) {SERR("failed");}对焦成功,跳出循环if(status ==  SENSOR_AF_FOCUSSED)break;if(cancel_autofocus) {cancel_autofocus = FALSE;break;}usleep(10000);i++;}/* Send the AF call back */switch (status) {case SENSOR_AF_FOCUSSED:af_msg.focus_state = CAM_AF_FOCUSED;break;default:af_msg.focus_state = CAM_AF_NOT_FOCUSED;break;}memset(&fdistance, 0, sizeof(fdistance));af_msg.f_distance = fdistance;memset(&bus_msg, 0, sizeof(mct_bus_msg_t));bus_msg.type = MCT_BUS_MSG_SENSOR_AF_STATUS;bus_msg.msg = (void *)&af_msg;bus_msg.size = sizeof(mct_bus_msg_af_status_t);bus_msg.sessionid = msg->sessionid;对焦成功,把消息发送到bus总线上去,这里类型为MCT_BUS_MSG_SENSOR_AF_STATUS,所以会发到bus_queue队列上去mct_module_post_bus_msg(msg->module,&bus_msg);cancel_autofocus = FALSE;SLOW("Setting Auto Focus message received");break;}case OFFLOAD_FUNC: {if (msg->offload_func) {msg->offload_func(msg->param1, msg->param2, msg->param3, msg->param4);} else {SERR("msg->offload_func is null");}}break;default:break;}
}
start_session小结

从pipeline中start_session最终都会走到各个module自己内部的session start,以sensor module为例:

  1. 根据传入的session id,查找到相关的sensor_bundle设备信息
  2. 创建一个线程,循环poll管道,读取来自kernel或者sensor module的消息
  3. 如果消息类型是自动对焦,则把消息发送到bus总线上去;如果是offload类型则会重载去执行一些函数

第三个 mct_pipeline_get_session_data

和start_session一样,不难得出,这个get_session最终也会调用module自己的get函数,如下:

boolean mct_pipeline_get_session_data(void *data, void *user_data)
{mct_pipeline_t *pipeline = (mct_pipeline_t *)user_data;mct_module_t *module = (mct_module_t *)data;if (!pipeline || !module) {return FALSE;}调用module自己的get_sessionif (module->get_session_data) {第二个参数是指针,说明是要把数据读到它里面module->get_session_data(module, &pipeline->session_data, pipeline->session);}return TRUE;
}

get_session_data数据结构指向的是module_sensor_get_session_data函数,这个函数主要就是读取其对应结构体里面的内容,如一些图像输出格式、相机位置以及3A信息等,然后将数据保存到此次pipeline的session_data里面去

第四个 mct_pipeline_set_session_data

set_session仍然是调用module的set session函数,反过来它是将上一个步骤得到的数据session_data又写回到module_sensor_ctrl_t结构体里面去


static boolean module_sensor_set_session_data(mct_module_t *module,void *set_buf, uint32_t sessionid)
{mct_pipeline_session_data_t          *frame_ctrl_data = NULL;module_sensor_ctrl_t                 *module_ctrl = NULL;sensor_bundle_info_t                  bundle_info;module_sensor_bundle_info_t           *s_bundle = NULL;uint32_t                              identity = 0;RETURN_ON_NULL(module);RETURN_ON_NULL(set_buf);frame_ctrl_data = (mct_pipeline_session_data_t *)set_buf;/* Extract module private */module_ctrl = (module_sensor_ctrl_t *)module->module_private;RETURN_ON_NULL(module_ctrl);memset(&bundle_info, 0, sizeof(sensor_bundle_info_t));identity = pack_identity(sessionid, 0);查找sensor_bundleRETURN_ON_FALSE(sensor_util_get_sbundle(module, identity, &bundle_info));s_bundle = bundle_info.s_bundle;RETURN_ON_NULL(s_bundle);设置session_data内容s_bundle->frame_ctrl.session_data = *frame_ctrl_data;s_bundle->capture_pipeline_delay =s_bundle->frame_ctrl.session_data.max_pipeline_frame_applying_delay;s_bundle->retry_frame_skip =s_bundle->frame_ctrl.session_data.min_isp_sw_frame_skip_retry;SHIGH("max delay %d report delay %d retry skip %d",frame_ctrl_data->max_pipeline_frame_applying_delay,frame_ctrl_data->max_pipeline_meta_reporting_delay,s_bundle->retry_frame_skip);return TRUE;
}

start session之添加stream流信息

在mct_pipeline_start_session启动session函数最后一步里面有一个mct_pipeline_start_stream_internal函数,将会为此次session添加stream信息,如下所示:

static void* mct_pipeline_start_stream_internal(mct_pipeline_t *pipeline)
{boolean rc = TRUE;mct_stream_t *stream = NULL;mct_pipeline_get_stream_info_t info;struct v4l2_event msg;struct msm_v4l2_event_data *data =(struct msm_v4l2_event_data*)&msg.u.data[0];cam_stream_info_t *stream_info;/*create new session based stream */data->session_id = pipeline->session;//MCT_SESSION_STREAM_ID = 15data->stream_id = MCT_SESSION_STREAM_ID;if (pipeline->add_stream) {CLOGI(CAM_MCT_MODULE,"Adding session stream streamid= 0x%x for session=%d",data->stream_id, pipeline->session);添加流信息,add_stream里面会create一个streamrc  = pipeline->add_stream(pipeline, data->stream_id);}
CLOGD(CAM_MCT_MODULE, "Allocating stream buffer");pipeline->session_stream.session_stream_info =malloc(sizeof(cam_stream_info_t));if (!pipeline->session_stream.session_stream_info) {CLOGE(CAM_MCT_MODULE, "session_stream_info allocation failed");return NULL;}CLOGD(CAM_MCT_MODULE, "Mapping stream buffer");映射,将上面创建的stream结构体内部的stream info信息映射到pipeline结构体中;这样后面的配置stream info两边都修改了,也就是pipeline.session_stream.session_stream_info = stream.buffers.stream_info if (pipeline->map_parm(pipeline) == FALSE) {CLOGE(CAM_MCT_MODULE, "stream map_param failed");return NULL;}配置stream的相关格式信息stream_info =(cam_stream_info_t *)pipeline->session_stream.session_stream_info;memset(stream_info, 0, sizeof(cam_stream_info_t));stream_info->stream_type = CAM_STREAM_TYPE_PARM;stream_info->fmt = CAM_FORMAT_YUV_420_NV12;stream_info->dim.width = 0;stream_info->dim.height = 0;stream_info->streaming_mode = CAM_STREAMING_MODE_CONTINUOUS;stream_info->buf_planes.plane_info.num_planes= 0;stream_info->num_bufs = 0;data->session_id = pipeline->session;data->stream_id = MCT_SESSION_STREAM_ID;info.check_type = CHECK_INDEX;info.stream_index = data->stream_id;因为流stream作为child添加到pipeline的结构体中,这里检查是否已经被添加进去stream = mct_pipeline_get_stream(pipeline, &info);这句代码很关键,宏定义又是宏定义,高通很多关键代码都用宏定义来处理,MCT_STREAM_LINK宏定义主要是检测stream结构体的link函数指针成员是否存在,如果存在就执行这个三行表达式的第二个,也就是调用stream的link函数,传递参数为自己本身stream(MCT_STREAM_LINK(stream)) ?(rc = (MCT_STREAM_LINK(stream))(stream)) : (rc = FALSE);....省略后面.....
}static boolean mct_pipeline_add_stream(mct_pipeline_t *pipeline,uint32_t stream_id)
{mct_stream_t *stream = NULL;if (!pipeline)return FALSE;创建一个mct_stream_tstream = mct_stream_new(stream_id);if (!stream)goto stream_failed;stream是子,pipeline是父,首先他们二者均有自己的mct_obj_t成员,第一步将pipelin的mct_obj加入到pipeline的mct_obj的parent里面去第二步将stream的mct_obj加入到pipeline的mct_obj的child里面去   if (!mct_object_set_parent(MCT_OBJECT_CAST(stream),MCT_OBJECT_CAST(pipeline))) {goto set_parent_failed;}return TRUE;
}

在mct_pipeline_start_stream_internal中,首先,创建mct_stream,把他加入到pipeline的子对象,使pipeline和stream之间建立好父子关系;然后,将stream中的info映射到pipeline的stream成员info中,并且配置这个stream info的具体信息,流type,图像格式fmt宽高等信息;最后,在调用stream自己的link函数,link内部很复杂,但是它主要的工作就是将stream与它需要的module进行绑定,并建立好module之间的数据流关系

stream之link

由pipeline如何调用link就不分析,我们直接进入link函数mct_stream_start_link:

static boolean mct_stream_start_link(mct_stream_t *stream)
{uint32_t sessionid;cam_stream_info_t    *stream_info;boolean              ret = FALSE;获取stream的buffers成员的stream_info成员,这个info就是上个mct_pipeline_start_stream_internal函数配置的info信息mct_stream_map_buf_t *info    = MCT_STREAM_STREAMINFO(stream);内部MCT_OBJECT_PARENT最终拿到的是pipeline  外部MCT_PIPELINE_MODULES则是拿到pipeline的modules成员,它是全局所有module的首节点,包括sensor、isp、等mct_list_t           *modules =MCT_PIPELINE_MODULES(MCT_OBJECT_PARENT(stream)->data);mct_pipeline_t *pipeline =MCT_PIPELINE_CAST((MCT_STREAM_PARENT(stream))->data);char *(*link_mod)[MAX_STREAM_MODULES] = NULL;stream->streaminfo.identity = pack_identity(sessionid, stream->streamid);stream->streaminfo.stream_type = stream_info->stream_type;stream->streaminfo.fmt = stream_info->fmt;stream->streaminfo.dim = stream_info->dim;stream->streaminfo.streaming_mode = stream_info->streaming_mode;stream->streaminfo.num_burst = stream_info->num_of_burst;stream->streaminfo.buf_planes = stream_info->buf_planes;stream->streaminfo.pp_config = stream_info->pp_config;stream->streaminfo.reprocess_config = stream_info->reprocess_config;stream->streaminfo.num_bufs = stream_info->num_bufs;stream->streaminfo.is_type = stream_info->is_type;stream->streaminfo.dis_enable = stream_info->dis_enable;stream->streaminfo.is_secure = stream_info->is_secure;stream->streaminfo.perf_mode = stream_info->perf_mode;stream->streaminfo.user_buf_info = stream_info->user_buf_info;stream->streaminfo.stream = stream;switch (stream->streaminfo.stream_type) {case CAM_STREAM_TYPE_POSTVIEW:case CAM_STREAM_TYPE_PREVIEW: .....session - stream链接,前面的函数配置为此类型case CAM_STREAM_TYPE_PARM: {CLOGI(CAM_MCT_MODULE, "Start linking Session-stream 0x%x",stream->streaminfo.identity);if (pipeline->session_data.sensor_format != FORMAT_YCBCR) {link_mod = param_bayer_mod;} else {yuv参数所需要的module,param_yuv_mod为全局参数,见本函数后面link_mod = param_yuv_mod;}}break;case CAM_STREAM_TYPE_CALLBACK:case CAM_STREAM_TYPE_SNAPSHOT:case CAM_STREAM_TYPE_VIDEO:case CAM_STREAM_TYPE_RAW:....有很多case.....配置连接ret = mct_stream_link_module_array(stream,link_mod);
}char *param_yuv_mod[][MAX_STREAM_MODULES] = {{"sensor","iface","pproc","imglib"},{},
};

这个link函数就是配置stream所需要的子module,为了完成我们的stream目标为CAM_FORMAT_YUV_420_NV12和CAM_STREAM_TYPE_PARM,需要param_yuv_mod这几个module,但是这几个module如何连接依赖当前stream,还要看看mct_stream_link_module_array函数:

static boolean mct_stream_link_module_array(mct_stream_t *stream,char *(*stream_type_mod)[MAX_STREAM_MODULES])
{boolean              ret = TRUE;获取stream的父pipelinemct_pipeline_t *pipeline =MCT_PIPELINE_CAST((MCT_STREAM_PARENT(stream))->data);获取所有的modulemct_list_t           *modules =MCT_PIPELINE_MODULES(MCT_OBJECT_PARENT(stream)->data);mct_module_t *module[MAX_STREAM_MODULES];int mod_type;int mod_row=0;int mod_col=0;int num_mod=0;如果传入的mod为空,返回if (stream_type_mod[mod_row][mod_col] == NULL) {return ret;}
while(1) {if (mod_col > MAX_STREAM_MODULES) {CLOGE(CAM_MCT_MODULE, "array overflow");return FALSE;}if (stream_type_mod[mod_row][mod_col]) {找到此stream配置的module,并存放在module这个局部数组里面,最终这个数组里面存放的就是此stream所需的module但是还没有完,还要建立module之间的连接关系module[num_mod] = mct_stream_get_module(modules,stream_type_mod[mod_row][mod_col]);if (module[num_mod] == NULL) {CLOGE(CAM_MCT_MODULE, "Null: %p",module[num_mod]);return FALSE;}mod_col++;num_mod++;} else {遍历找到的module数组for (num_mod=0; num_mod< mod_col;num_mod++) {找到的第一个module,其类型为sourceif (num_mod == 0 && mod_row ==0) {      mod_type = MCT_MODULE_FLAG_SOURCE;找到最后一个module,它为一个sinkmode} else if (num_mod == (mod_col-1)) {mod_type = MCT_MODULE_FLAG_SINK;中间的module则为Indexable} else {mod_type = MCT_MODULE_FLAG_INDEXABLE;}设置module的type_list里面的成员,主要是相对于stream,这个module是source、sink还是其他的module[num_mod]->set_mod(module[num_mod],mod_type,stream->streaminfo.identity);}for (num_mod=0; num_mod< (mod_col-1);num_mod++) {if (mod_row!=0) {...这里不会执行,因为只有一行module配置....} else {主要就是将参数中两个module依次加入到stream的子children里面ret = mct_stream_link_modules(stream,module[num_mod],module[num_mod+1], NULL);if (ret == FALSE) {CLOGE(CAM_MCT_MODULE, "Linking failed");return FALSE;}}}mod_row++;mod_col=0;num_mod=0;                    if (stream_type_mod[mod_row][mod_col] == NULL) {break;}}};if (ret == FALSE) {CLOGE(CAM_MCT_MODULE, "link failed");return FALSE;}return ret;
}

就这样把stream相关的module都配置到其子children里面去了,link也总算完成了!总的来说,stream的link就是就是把相关的module设置到stream的子children对象里面去,并且children里面的排序分别是source/中间/sink模块,与此同时,这些模块通过port来连接,port内部则又有peer成员来确定他们之间的相互关系

再次小结start_session框架图

值得注意的是纵向创建stream时,首先配置stream目标,此次流是什么样的流?然后这个流需要哪些module支持,如sensor和isp这些等等,link好后,将相关module添加到stream的子对象中,最后建立这些module之间的关系;

最后,下面这两个线程就会使用这些建立好的关系!


start_session两个重要的线程

第一个线程mct_controller_thread_run

此线程主要是轮询mct_controller_t上的serv_cmd_q队列,取数据,然后执行操作的,

static void* mct_controller_thread_run(void *data)
{mct_controller_t  *mct_this;mct_process_ret_t *mct_ret = NULL;mct_process_ret_t proc_ret;mct_serv_msg_t    *msg;timer_t mct_timerid;int mct_t_ret = 0; struct timespec timeToWait;mct_this = (mct_controller_t *)data;mct_this->mct_tid = pthread_self();/* create a timer */mct_t_ret = mct_util_create_timer(&mct_timerid);.....do { pthread_mutex_lock(&mct_this->mctl_mutex);serv_cmd计数器为0就等待命令if (!mct_this->serv_cmd_q_counter) {pthread_cond_wait(&mct_this->mctl_cond, &mct_this->mctl_mutex);}    while (1) {pthread_mutex_lock(&mct_this->serv_msg_q_lock);取出serv_cmd_q中的消息msg = (mct_serv_msg_t *)mct_queue_pop_head(mct_this->serv_cmd_q);pthread_mutex_unlock(&mct_this->serv_msg_q_lock);取出的消息为空,退出内存循环if (!msg) {break;}消息数量减一mct_this->serv_cmd_q_counter--;pthread_mutex_unlock(&mct_this->mctl_mutex);mct_ret = (mct_process_ret_t *)malloc (sizeof(mct_process_ret_t));if (!mct_ret) {CLOGE(CAM_MCT_MODULE, "Out of Memory, Malloc failed");goto close_mct;}处理消息,获取返回结果*mct_ret = mct_controller_proc_serv_msg_internal(mct_this, msg);free(msg);msg = NULL;如果处理结果为删除session会话,就结束当前线程if (mct_ret->type == MCT_PROCESS_RET_SERVER_MSG  &&mct_ret->u.serv_msg_ret.msg.msg_type == SERV_MSG_HAL  &&mct_ret->u.serv_msg_ret.msg.u.hal_msg.id == MSM_CAMERA_DEL_SESSION)   {goto close_mct;}.......       }} while(1);......
}

到这一步,只能看出取出消息,然后调用mct_controller_proc_serv_msg_internal来处理消息,再继续往下看的同时,建议你先看看文章最上面的mct_serv_msg_t结构体内部结构,然后在看mct_controller_proc_serv_msg_internal函数:

static mct_process_ret_t mct_controller_proc_serv_msg_internal(mct_controller_t *mct, mct_serv_msg_t *msg)
{serv线程的返回值类型mct_process_ret_tmct_process_ret_t ret;mct_pipeline_t    *pipeline;初始化返回值                                                                                                                                                                                                                                                                                       memset(&ret, 0x00, sizeof(mct_process_ret_t));ret.type = MCT_PROCESS_RET_SERVER_MSG;ret.u.serv_msg_ret.error = TRUE;.......ret.u.serv_msg_ret.msg = *msg;pipeline = mct->pipeline;switch (msg->msg_type) {来自socket的消息,也就是vendor层另一边还有一个socket进程,此文还未提及case SERV_MSG_DS: {这部分主要会调用pipeline的map映射操作if ((msg->u.ds_msg.operation == CAM_MAPPING_TYPE_FD_BUNDLED_MAPPING ||msg->u.ds_msg.operation == CAM_MAPPING_TYPE_FD_MAPPING)&& pipeline->map_buf) {ret.u.serv_msg_ret.error = pipeline->map_buf(&msg->u.ds_msg, pipeline);} else if (msg->u.ds_msg.operation == CAM_MAPPING_TYPE_FD_UNMAPPING &&pipeline->unmap_buf) {ret.u.serv_msg_ret.error = pipeline->unmap_buf(&msg->u.ds_msg, pipeline);}}break;case SERV_MSG_HAL:来自hal的消息if (pipeline->process_serv_msg)pipeline处理ret.u.serv_msg_ret.error = pipeline->process_serv_msg(&msg->u.hal_msg,pipeline);break;default:break;}return ret;
}

如上,处理hal的消息又进入到pipeline了,这个消息是从上往下传递的,hal–>vendor;而process_serv_msg是一个函数指针:

pipeline->process_serv_msg= mct_pipeline_process_serv_msg;

这种操作在mct内很常见,各个module的结构体内部都会有许多函数指针,而module之间调用就会通过这种指针调用;所以当你找不到函数时,去module的初始化里面去找,说不定它就是个函数指针:

static boolean mct_pipeline_process_serv_msg(void *message,mct_pipeline_t *pipeline)
{struct v4l2_event *msg = (struct v4l2_event *)message;boolean           ret = TRUE;struct msm_v4l2_event_data *data =(struct msm_v4l2_event_data *)(msg->u.data);if (!message || !pipeline || data->session_id != pipeline->session)return FALSE;switch (msg->id) {设置相机参数case MSM_CAMERA_SET_PARM:ret = mct_pipeline_process_set(data, pipeline);break;获取相机参数case MSM_CAMERA_GET_PARM:/* process config_w  */ret = mct_pipeline_process_get(data, pipeline);break;结束sessioncase MSM_CAMERA_DEL_SESSION: {/* for session ending:* a session has ONLY one child */if (MCT_PIPELINE_CHILDREN(pipeline)) {MCT_OBJECT_LOCK(pipeline);/* Delete streams */mct_list_free_all(MCT_PIPELINE_CHILDREN(pipeline),mct_pipeline_delete_stream);MCT_PIPELINE_CHILDREN(pipeline) = NULL;MCT_PIPELINE_NUM_CHILDREN(pipeline) = 0;MCT_OBJECT_UNLOCK(pipeline);}}break;default:/* something wrong */ret = FALSE;break;} /* switch (msg->msg_type) */return ret;
}

这个函数也很简单,从上层传递下来的就是设置/获取相机参数,或者结束session会话;这里我们以set参数为例跟进去看看,

static boolean mct_pipeline_process_set(struct msm_v4l2_event_data *data,mct_pipeline_t *pipeline)
{boolean      ret = TRUE;mct_stream_t *stream = NULL;mct_pipeline_get_stream_info_t info;if (data->command != CAM_PRIV_PARM)CLOGI(CAM_MCT_MODULE, "command=%x", data->command);第一个switch会根据指令大范围摔选相关的stream流,并处理一些共性逻辑判断,如下switch (data->command) {case CAM_PRIV_STREAM_INFO_SYNC:case MSM_CAMERA_PRIV_STREAM_ON:case MSM_CAMERA_PRIV_STREAM_OFF:case MSM_CAMERA_PRIV_DEL_STREAM:case CAM_PRIV_STREAM_PARM: {info.check_type   = CHECK_INDEX;info.stream_index = data->stream_id;CLOGL(CAM_MCT_MODULE, "stream id: %x", data->stream_id);stream = mct_pipeline_get_stream(pipeline, &info);if (!stream) {CLOGE(CAM_MCT_MODULE, "Couldn't find stream id: %x",data->stream_id);return FALSE;}如果是stream启动指令,并且stream已经启动了,就直接返回if (MSM_CAMERA_PRIV_STREAM_ON == data->command &&MCT_ST_STATE_RUNNING == stream->state) {return TRUE;}如果是stream结束指令,并且stream已经结束了,就直接返回else if (MSM_CAMERA_PRIV_STREAM_OFF == data->command &&MCT_ST_STATE_IDLE == stream->state) {return TRUE;}}break;case CAM_PRIV_PARM:case CAM_PRIV_PREPARE_SNAPSHOT:case CAM_PRIV_START_ZSL_SNAPSHOT:case CAM_PRIV_STOP_ZSL_SNAPSHOT:case CAM_PRIV_CANCEL_AUTO_FOCUS:case CAM_PRIV_DO_AUTO_FOCUS:case CAM_PRIV_SYNC_RELATED_SENSORS: {info.check_type   = CHECK_INDEX;info.stream_index = MCT_SESSION_STREAM_ID;stream = mct_pipeline_get_stream(pipeline, &info);if (!stream) {CLOGE(CAM_MCT_MODULE, "Couldn't find stream id: %x",data->stream_id);return FALSE;}}break;default:break;}精准处理,根据不同的指令,不同的操作switch (data->command) {添加一条新的stream    case MSM_CAMERA_PRIV_NEW_STREAM: {CLOGD(CAM_MCT_MODULE, "Adding new stream: id [0%x]", data->stream_id);if (pipeline->add_stream) {MCT_PROF_LOG_BEG(PROF_MCT_STREAMADD, "id:", data->stream_id);增加streamret = pipeline->add_stream(pipeline, data->stream_id);if(FALSE == ret)MCT_PROF_LOG_END();} else {ret = FALSE;}}break;stream 同步,会导致stream和其相关的module连接起来,module作为stream的子对象case CAM_PRIV_STREAM_INFO_SYNC: {拿到此流的info配置信息,包括图像格式。宽高等信息if (!MCT_STREAM_STREAMINFO(stream)) {没有拿到,说明stream有问题,返回ret = FALSE;else 说明拿到stream的info信息} else {MCT_PROF_LOG_BEG(PROF_MCT_STREAM_LINK, "id", stream->streamid,"type", stream->streaminfo.stream_type);这句代码和pipeline启动session后,最后几行代码一样,属于link stream with module(MCT_STREAM_LINK(stream)) ?(ret = (MCT_STREAM_LINK(stream))(stream)) : (ret = FALSE);if (FALSE == ret) {stream->streaminfo.identity,stream->streaminfo.stream_type);} else {。。.。}MCT_PROF_LOG_END();}启动 or 结束stream信息case MSM_CAMERA_PRIV_STREAM_ON:case MSM_CAMERA_PRIV_STREAM_OFF:{mct_event_t         cmd_event;mct_event_control_t event_data;char command[20];boolean ret = TRUE;if (data->command == MSM_CAMERA_PRIV_STREAM_ON) {event_data.type = MCT_EVENT_CONTROL_STREAMON;strlcpy (command, "STREAM-ON", sizeof(command));} else {event_data.type = MCT_EVENT_CONTROL_STREAMOFF;strlcpy (command, "STREAM-OFF", sizeof(command));}如果在pipeline的子对象running状态的stream只有一条,并且当前是结束指令if ( (1 == pipeline->stream_on_cnt) &&(data->command == MSM_CAMERA_PRIV_STREAM_OFF) ) {MCT_OBJECT_LOCK(pipeline);暂不清楚这个frame_num_idx_list是什么,但是这里就是释放所有的frame_num_idx_listmct_list_free_all(pipeline->frame_num_idx_list,mct_stream_free_frame_num_list);pipeline->frame_num_idx_list = NULL;MCT_OBJECT_UNLOCK(pipeline);if (!MCT_QUEUE_IS_EMPTY(pipeline->super_param_queue)) {发送之前的指令mct_pipeline_flush_super_param_queue(pipeline);}}event_data.control_event_data = (void *)&stream->streaminfo;CLOGI(CAM_MCT_MODULE, " %s on stream 0x%x stream type=%d",command, stream->streaminfo.identity, stream->streaminfo.stream_type);/打包指令,也就是将一种数据结构转换成另一种结构,把数据event_data和指令都会封装到cmd_event里面ret = mct_pipeline_pack_event(MCT_EVENT_CONTROL_CMD,(pack_identity(MCT_PIPELINE_SESSION(pipeline), data->stream_id)),MCT_EVENT_DOWNSTREAM, &event_data, &cmd_event);if (ret == FALSE) {CLOGE(CAM_MCT_MODULE, "Error in packing event");break;}继续发送指令if (pipeline->send_event) {发送指令,调用pipeline的send_event,其内部又是调用stream的send_eventret = pipeline->send_event(pipeline, data->stream_id, &cmd_event);if (TRUE == ret) {启动加一if (data->command == MSM_CAMERA_PRIV_STREAM_ON) {stream->state = MCT_ST_STATE_RUNNING;if ((stream->streaminfo.stream_type != CAM_STREAM_TYPE_METADATA) &&(stream->streaminfo.stream_type != CAM_STREAM_TYPE_OFFLINE_PROC)) {加一操作pipeline->stream_on_cnt++;}结束减一} else {stream->state = MCT_ST_STATE_IDLE;if ((stream->streaminfo.stream_type != CAM_STREAM_TYPE_METADATA) &&(stream->streaminfo.stream_type != CAM_STREAM_TYPE_OFFLINE_PROC)) {pipeline->stream_on_cnt--;if (0 == pipeline->stream_on_cnt) {if (pipeline->bus) {pipeline->bus->prev_sof_id = 0;  /* Reset SOF tracker */}}}}} else {.....}}else {CLOGE(CAM_MCT_MODULE, "send_event not registered");ret = FALSE;}MCT_PROF_LOG_END();}break;           ......}case......后面还有很多case

此函数相对较长,主要是根据case命令,执行不同的操作,这里以这MSM_CAMERA_PRIV_STREAM_ON来跟踪分析,些命令都来自上层;上层应用都是根据session来回话的,而传入的参数data里面有session和streamid,这里会根据stream id找到pipeline下子对象的相同id的stream,然后对其发送事件;几乎所有的case条件,都会先打包封装参数,然后调用pipeline的sent_event事件去操作,不难猜出sent_event是一个函数指针,最终肯定走到stream里面去:

send_event == mct_pipeline_send_event
static boolean mct_pipeline_send_event(mct_pipeline_t *pipeline,uint32_t stream_id, mct_event_t *event)
{boolean ret = TRUE;mct_stream_t *stream = NULL;mct_pipeline_get_stream_info_t info;if (!pipeline || !event)return FALSE;info.check_type   = CHECK_INDEX;info.stream_index = stream_id;stream = mct_pipeline_get_stream(pipeline, &info);if (!stream) {CLOGE(CAM_MCT_MODULE, "Couldn't find stream");return FALSE;}调用stream的send_evenret = stream->send_event(stream, event);return ret;
}

是这样吧!进入stream吧!

stream->send_event     = mct_stream_send_event;
static boolean mct_stream_send_event(mct_stream_t *stream, mct_event_t *event)
{mct_module_t *src_module = NULL;boolean ret = FALSE;mct_list_t *sinkports;mct_port_t *port = NULL;if (stream->streaminfo.stream_type == CAM_STREAM_TYPE_METADATA) {.....} else if ((stream->streaminfo.stream_type == CAM_STREAM_TYPE_OFFLINE_PROC)&&((stream->streaminfo.reprocess_config.\pp_feature_config.feature_mask &(CAM_QCOM_FEATURE_METADATA_PROCESSING | CAM_QCOM_FEATURE_METADATA_BYPASS)))) {....} else {宏定义判断这个stream必须有子对象module才行if (MCT_STREAM_CHILDREN(stream)) {后面这个宏定义依次是取mct_stream=>mct_obj->children->data,有可能stream有多个module,而这里取出来的是第一个添加进去的module,也就是源modulesrc_module = (mct_module_t *)(MCT_STREAM_CHILDREN(stream)->data);}第一个子对象必须source,因为最终图像数据都从第一个module出来if (!src_module)return FALSE;module根据标识identity是此流的source,并且这个module必须有process_event事件,就去执行if ((mct_module_find_type(src_module, event->identity)== MCT_MODULE_FLAG_SOURCE) && src_module->process_event) {ret = src_module->process_event(src_module, event);} else {.......}}return ret;
}

这么一看stream_on事件又会传递到其相关的module下面去,执行module的process_event函数指针,这样正常,启动stream肯定要去配置其子对象module能正常工作才行,stream子对象有哪些module呢? 这个和你一开始创建stream时配置有关系,在mct_stream.c源文件头部有很多配置,如下是部分展示:

本文前面在start_session部分有提及创建stream时会有一些配置,其中配置选择了param_yuv_mod,这里就以这个为讲解,上面代码的src_module->process_event就会执行sensor module的事件,process_event;我们跳转到sensor module里面去执行,sensor中此process_event也是一个函数指针,设置在这里

mct_module_set_process_event_func(module,module_sensor_module_process_event);
static boolean module_sensor_module_process_event(mct_module_t *module,mct_event_t *event)
{boolean                      ret = TRUE;int32_t                      rc = SENSOR_SUCCESS;module_sensor_ctrl_t        *module_ctrl = NULL;mct_event_control_t         *event_ctrl = NULL;sensor_bundle_info_t         bundle_info;struct timespec              ts;module_ctrl = (module_sensor_ctrl_t *)module->module_private;RETURN_ON_NULL(module_ctrl);event_ctrl = &event->u.ctrl_event;准备抓图if (event_ctrl->type == MCT_EVENT_CONTROL_PREPARE_SNAPSHOT) {sensor_output_format_t output_format;mct_bus_msg_t bus_msg;memset(&bus_msg, 0, sizeof(mct_bus_msg_t));module_sensor_params_t *module_sensor_params = NULL;bundle_info.s_bundle->state = 0;bundle_info.s_bundle->regular_led_trigger = 0;SUB_MODULE_SENSOR是其module子设备module_sensor_params =bundle_info.s_bundle->module_sensor_params[SUB_MODULE_SENSOR];向sensor子设备发送获取sensor格式指令rc = module_sensor_params->func_tbl.process(module_sensor_params->sub_module_private,SENSOR_GET_SENSOR_FORMAT, &output_format);SLOW("in Prepare snapshot, sensor type is %d\n", output_format);if (output_format == SENSOR_YCBCR) {bus_msg.sessionid = bundle_info.s_bundle->sensor_info->session_id;bus_msg.type = MCT_BUS_MSG_PREPARE_HW_DONE;cam_prep_snapshot_state_t state;state = DO_NOT_NEED_FUTURE_FRAME;bus_msg.msg = &state;bus_msg.size = sizeof(cam_prep_snapshot_state_t);向bus总线上post消息,说我已经准备好抓图,msg会推送到bus的bus_queueif (mct_module_post_bus_msg(module,&bus_msg)!=TRUE)SERR("Failure posting to the bus!");return TRUE;}}
switch (event_ctrl->type) {启动stream指令        case MCT_EVENT_CONTROL_STREAMON:MCT_PROF_LOG_BEG(PROF_SENSOR_STREAM_ON, "stream type", module_ctrl->streaminfo.stream_type);SLOW("ide %x MCT_EVENT_CONTROL_STREAMON",event->identity);/* Set the sensor stream */ret = module_sensor_set_sensor_stream(bundle_info.s_bundle);BREAK_ON_FALSE(ret);memcpy(&module_ctrl->streaminfo, event->u.ctrl_event.control_event_data,sizeof(mct_stream_info_t));向module下的port发送stream on指令ret = port_sensor_handle_stream_on(module, event, &bundle_info);BREAK_ON_FALSE(ret);break;case .....
}

此函数也相对较长,有很多case语句,这里就只看MCT_EVENT_CONTROL_STREAMON,sensor module又将事件发送到port上去,port才是最终的执行者;

boolean port_sensor_handle_stream_on(mct_module_t *module, mct_event_t *event,sensor_bundle_info_t *bundle_info)
{boolean ret = TRUE;mct_port_t *port = NULL;if (bundle_info->s_bundle->sensor_num_fast_aec_frame_skip &&bundle_info->s_bundle->fast_aec_required)ret = port_sensor_handle_stream_on_fastaec(module, event, bundle_info);else走正常逻辑ret = port_sensor_handle_stream_on_normal(module, event, bundle_info);RETURN_ON_FALSE(ret);/* Set stream ON flag */说明已经stream on了,设置stream中的状态标志ret = sensor_util_set_stream_on(module, event->identity, TRUE);                                                                                                                                                                                                                       RETURN_ON_FALSE(ret);return ret;
}static boolean port_sensor_handle_stream_on_normal(mct_module_t *module,mct_event_t *event,sensor_bundle_info_t *bundle_info)
{boolean ret = TRUE;调用module sensor中各个子设备,配置其信息,使stream on ret = module_sensor_stream_on(module, event, bundle_info->s_bundle);RETURN_ON_FALSE(ret);return TRUE;
}

sensor module的stream on:

boolean module_sensor_stream_on(mct_module_t *module,mct_event_t *event, module_sensor_bundle_info_t *s_bundle)
{boolean                       ret = TRUE;int32_t                       rc = SENSOR_SUCCESS;int32_t                       i = 0;module_sensor_params_t        *module_sensor_params = NULL;sensor_get_t                  sensor_get;sensor_output_format_t        output_format;int32_t                       stream_on_count;mct_stream_info_t* stream_info =(mct_stream_info_t*) event->u.ctrl_event.control_event_data;sensor_set_res_cfg_t stream_on_cfg;int32_t bundle_id = -1;boolean stream_on_flag = FALSE;module_sensor_port_bundle_info_t *bundle_info = NULL;int32_t delay_en = 1;sensor_thread_msg_t msg;int32_t nwrite = 0;module_sensor_params_t *stereo_peer_module_sensor_params = NULL;....module_sensor_params = s_bundle->module_sensor_params[SUB_MODULE_SENSOR];配置sensor子设备rc = module_sensor_params->func_tbl.process(module_sensor_params->sub_module_private,SENSOR_SET_DELAY_CFG, (void*)&delay_en);配置LEDmodule_sensor_params_t *led_module_params =s_bundle->module_sensor_params[SUB_MODULE_LED_FLASH];if (led_module_params->func_tbl.process != NULL) {rc = led_module_params->func_tbl.process(led_module_params->sub_module_private, LED_FLASH_SET_TORCH, NULL);}这块里面涉及到大量的底层交互... 配置完成后}
server thread 小结

到这里,终于把线程中大部分任务看完了;总的来说:

  1. 取mct_controller中server_cmd数据处理
  2. 分析参数数据,然后依次交给pipeline --> stream -> module -> port处理
  3. 设置相关的状态变量

    如上图,事件最终在port模块会完结,最后在将成功或者失败的消息发送到mct_bus_t模块的数据队列上去;将由下一个线程将消息回调给上层应用

第二个线程mct_bus_handler_thread_run

这个线程相对简单,主要是将数据由底层传递给上层,一步一步分析:

static void* mct_bus_handler_thread_run(void *data)
{mct_process_ret_t  proc_ret;mct_bus_msg_t     *bus_msg;mct_controller_t* mct_obj = (mct_controller_t *)data;if(!mct_obj) {CLOGE(CAM_MCT_MODULE, "Invalid pointer for mct object");return NULL;}do {pthread_mutex_lock(&mct_obj->mctl_bus_handle_mutex);如果bus总线上的priority_queue队列长度为0,说明没有数据,wait等待数据if(!mct_obj->pipeline->bus->priority_queue->length) {pthread_cond_wait(&mct_obj->mctl_bus_handle_cond,&mct_obj->mctl_bus_handle_mutex);}pthread_mutex_unlock(&mct_obj->mctl_bus_handle_mutex);/* Received Signal from Pipeline Bus */while (1) {pthread_mutex_lock(&mct_obj->pipeline->bus->priority_q_lock);从bus总线的priority_queue取数据bus_msg = (mct_bus_msg_t *)mct_queue_pop_head(mct_obj->pipeline->bus->priority_queue);pthread_mutex_unlock(&mct_obj->pipeline->bus->priority_q_lock);取出的消息为空,退出内层循环if (!bus_msg) {break;}消息类型为close camera,退出线程if (bus_msg->type == MCT_BUS_MSG_CLOSE_CAM) {goto thread_exit;}//处理消息msgproc_ret = mct_controller_proc_bus_msg_internal(mct_obj, bus_msg);}} while(1);....}return NULL;
}

轮询bus中的priority_queue任务队列,函数请看注释,接着看mct_controller_proc_bus_msg_internal,处理bus msg:

static mct_process_ret_t mct_controller_proc_bus_msg_internal(mct_controller_t *mct, mct_bus_msg_t *bus_msg)
{mct_process_ret_t ret;mct_pipeline_t    *pipeline;ret.u.bus_msg_ret.error = TRUE;ret.type = MCT_PROCESS_RET_BUS_MSG;if (!mct || !bus_msg || !mct->pipeline) {return ret;}//设置状态mct_controller_set_thread_state(mct, MCT_THREAD_STATE_RUNNING);ret.u.bus_msg_ret.error = FALSE;ret.u.bus_msg_ret.msg_type = bus_msg->type;ret.u.bus_msg_ret.session = bus_msg->sessionid;pipeline = mct->pipeline;....请求frameif (bus_msg->type == MCT_BUS_MSG_CONTROL_REQUEST_FRAME) {ret.u.bus_msg_ret.error = FALSE;if (!mct_pipeline_control_hw_state(pipeline, bus_msg->msg)) {CLOGE(CAM_MCT_MODULE, "Failed to set HW module state");return ret;}}if (bus_msg->type == MCT_BUS_MSG_SEND_HW_ERROR ||bus_msg->type == MCT_BUS_MSG_EZTUNE_JPEG ||bus_msg->type == MCT_BUS_MSG_EZTUNE_RAW) {向应用层发送回调ret.u.bus_msg_ret.error = mct_controller_send_cb(pipeline, bus_msg->type);.....return ret;}......if(MCT_BUS_MSG_ISP_RD_DONE == bus_msg->type) {if(!mct_controller_handle_offline_meta_proc(pipeline, bus_msg)) {......}}
if (bus_msg->type == MCT_BUS_MSG_CAC_STAGE_DONE) {向应用层发送回调ret.u.bus_msg_ret.error = mct_controller_send_cb(pipeline, bus_msg->type);if (ret.u.bus_msg_ret.error == FALSE) {CLOGE(CAM_MCT_MODULE, "Failed to send callback to HAL for type = %d",bus_msg->type);return ret;}}设置状态mct_controller_set_thread_state(mct, MCT_THREAD_STATE_IDLE);return ret;
}

上面函数大多数都会执行mct_controller_send_cb发送回调事件,这个回调事件,然后又统一调用mct_controller_notify_hal_internal_event将事件通知给上层

static boolean mct_controller_notify_hal_internal_event(mct_pipeline_t *pipeline, cam_event_type_t command)
{mct_process_ret_t  proc_ret;struct v4l2_event *event;cam_event_t cam_event;int rc;mct_controller_t *mct = NULL;mm_camera_shim_event_handler_func evt_cb;if (!pipeline) {CLOGE(CAM_MCT_MODULE, "Pipeline ptr NULL");return FALSE;}mct = pipeline->controller;if (!mct) {CLOGE(CAM_MCT_MODULE, "NULL mct_controller object.");return FALSE;}cam_event.server_event_type = command;cam_event.status = CAM_STATUS_SUCCESS;回调,start_session调用vendor层时传递下来的回调evt_cb = (mm_camera_shim_event_handler_func)mct->event_cb;if (!evt_cb) {CLOGE(CAM_MCT_MODULE, "Callback not registered");return FALSE;}执行回调rc = evt_cb(pipeline->session,&cam_event);if (rc == FALSE) {CLOGE(CAM_MCT_MODULE, "Failed to send callback cmd = %d", command);return FALSE;}
}

这里这个线程工作就完了,然后又会继续轮询数据,可能大家有个疑惑,轮询的源头,bus中的priority_queue中数据哪里来?当然是从kernel底层来了,当然也有可能是从vendor这里就有返回,比如启动session,完成后,就会直接往bus中post一个小小说完成了,进而发送到上层;这个数据会发送到hal层的evt thread线程,由这个线程发送到App上

bus thread小结

本文总结

为了更好的理解mct组成,首先要知道camera模块的硬件组成有哪些,camera许多硬件模块都对应了软件层的module;本文从两条线来阐述:
一条是初始化init过程,会依次初始化各个module模块
另一条是start session业务,会创建相关的通信结构体,controller、pipeline、bus、stream以及port和module等;
最后,start session会创建两个线程;
mct_controller_thread_run线程是数据从上到下的传递,它会贯通start session创建的相关结构体;
mct_bus_handler_thread_run则是数据从下到上的传递,是数据的回调过程
本文只是学习了mct整体架构的组成和运作逻辑部分,而关于camera更专业的地方,如图像调优、3A、turning则未深入查看了,鉴于本人水平有限,加之网上关于高通mct资料相对较少,只能摸索出这个名堂了!如有不对的,望指正!

解析高通vendor层mct框架相关推荐

  1. 高通HAL层之Sensor HAL

    高通的HAL层其实分为两种,一种是直接从kernel这边报数据上来的,由sensor HAL层来监听,另一种是走ADSP的模式,HAL层是通过qmi的形式进行监听的: 走ADSP架构的可以看下面的博客 ...

  2. 高通平台fingerprint指纹框架

    指纹是android系统中目前应用比较广发的一种安全验证手段,它使得我们的手机安全得到了极大的提高,同时指纹它也拥有了极高权限,这就意味着,对于指纹这个软件需要一个绝对安全的运行环境,让外界很难突破去 ...

  3. 我所理解的高通平台Lcd驱动框架

    帧缓冲(framebuffer)是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作.用户不必关系物理显示 ...

  4. 深度解析高通RF360移动射频前端解决方案

    前段时间,微波射频网报道了高通新推出的RF360射频前端解决方案(查看详情),新产品首次实现了单个移动终端支持全球所有4G LTE制式和频段的设计.接下来让我们一起深度解析RF360全新移动射频前端解 ...

  5. 完全解析高通sensor新架构SEE

    PS:博文部分图片无法加载,根据自己找到的信息,附上部分截图,后面持续补充. 1.框架 2.Sensor Hal层代码分析 vendor/qcom/proprietary/sensors-see$

  6. 高通芯片联机读取修改串码 meid ESN wifi 蓝牙 sn等参数的操作解析{二}

    上次我发了几个相关联机读写参数的帖子.很多友友询问有没有其他相关软件来解读参数的教程.今天就来个续集来解析参数读写 关于安卓机型写串码 改串码 端口开启和基带qcn等一些经验 高通联机修改IMEI等参 ...

  7. 高通机型备份字库 备份 制作线刷包的几种方式解析{二}

    MTK芯片机型的备份单分区与全字库各种方法解析与相关教程 高通 mtk 展讯等芯片机型读取 备份手机全字库分区 的一些操作解析 高通备份线刷包工具软件 备份自己机型的线刷包 前面几个帖子列举了可以备份 ...

  8. 高通camera调试

    高通camera驱动分析 ./qcom/proprietary/mm-still/codec_v1/omx/jpeg_encoder/Android.mk:15:CHROMATIX_VERSION : ...

  9. 高通平台android开发总结

    http://www.cnblogs.com/yuzaipiaofei/archive/2012/07/24/4124179.html 1.高通平台android开发总结 1.1 搭建高通平台环境开发 ...

  10. 高通平台android 环境配置编译及开发经验总结

    完全转自:http://blog.csdn.net/dongwuming/article/details/12784535 1.高通平台android开发总结 1.1 搭建高通平台环境开发环境 在高通 ...

最新文章

  1. Crontab运行php脚本
  2. python中的logger模块详细讲解
  3. 搜狐视频怎么设置自动连播
  4. apache+php
  5. 《计算机操作系统》思维导图
  6. 幼儿识字软件测试自学,2016幼儿识字APP哪家强?最新测评出炉!
  7. sockets: SCTP
  8. Freebase Data Dump结构初探
  9. 二分法(Bisection)求解单根(python,数值积分)
  10. 第二天 熟悉ue4工具 及快捷键
  11. DSP28335学习记录(四)——ADC、DMA
  12. 账户注销及用户信息删除的合规实务问答
  13. 为什么Android系统比ios系统卡?
  14. 微信营销如何提升转化率与购买率
  15. Vb下调用Help文件 (转)
  16. 奶爸日记12 - 小鱼儿
  17. MRS离线数据分析:通过Flink作业处理OBS数据
  18. 修改管理员信息php,修改管理员_ThinkPHP_大笨熊_IT技术平台
  19. 最小点权覆盖集最大点权独立集
  20. 如何用Keynote绘制app原型图

热门文章

  1. 安卓pdf阅读器_PDF阅读用哪款软件好?推荐这7款,简单又好用!
  2. eda数字竞赛抢答器
  3. hp服务器装vm系统,服务器虚拟化ESXi 5.5安装过程(HP)
  4. Access新手到高手视频教程 109讲
  5. excel文件修复工具_七款免费的PDF处理工具
  6. Linux安装Java8
  7. PIC单片机应用开发实践教程(五): 烧录器简介
  8. 廖雪峰python笔记
  9. 小乌龟SVN安装和使用
  10. 微信批量扫码进群系统