目录 3
1. Introduction 4
2. 高通Camera架构之模块简介 5
2.1 定义Camera模块结构 6
2.2 Camera模块代码结构 6
3. ISP模块 8
3.1 ISP模块基础 8
3.2 ISP模块总体初始化框图 10
3.3 ISP子模块bpc(Bad Pixel Correction)初始化流程及框图 11
1. Introduction
本文主要讲解vendor层框架基础。
2. 高通Camera架构之模块简介
1) Camera的所有功能被划分为不同的模块,让模块自己来决定自己的事情(高内聚,低耦合);
2) 模块有统一的接口和格式;
3) 模块中有端口,通过端口把模块连接起来,又把模块挂在总线上;
4) 每一个端口的连接就是一个流,这些流用pipeline来管理;
5) 每次启动一个camera就创建一个会话,由这个会话来管理此camera的一切事物。对于每一个会话,模块是共享的,它可以是camera的硬件资源也可以是其它资源(如一些软件算法等资源)。
例如:Bayer preview的流如下图:
|——>stats模块
sensor模块 <——>ispif模块<——>isp模块<——>pproc模块<——>imagelib模块
2.1 定义Camera模块结构
1)端口,端口分为src、sink、inter,如果这个模块只有source端口,那么它就是一个src模块;如果只有sink端口就是sink模块,如果都有就是中间模块(ISP模块即属于inter模块)。没有端口的模块是不能连接到流中的,但他可以完成一些其他的功能,比如接收引擎的设置,报告事件到bus等。
2)模块线程,每个模块可以有一个线程来处理模块的事情。一个线程对应一个队列,线程就是从队列中取出数据处理,然后应答回去;
3)总线回调,当一个模块向总线注册时,总线向其提供一个回调函数,当模块有事件发生时,调用这个函数向bus发消息,然后总线把这个消息提交给管道,管道把这个消息顺着流发下去;
4)模块的get、set以及process函数,可以参看aecawb_thread_handler()函数awb 和aec 相关的处理。
模块组织结构图如下:
reference: 80-NE717-1_C_MSM8974_APQ8074_MSM8x26_Linux_Camera_SDD page 56
2.2 Camera模块代码结构
server-image 是qcamera_daemon 主函数所在目录;media-controller 目录包
含的主要业务及框架代码:
mct:包含了引擎、pipiline、bus、module、stream及event等定义及封装。
modules——各模块代码
模块目录如下图:
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模块。
3. ISP模块
3.1 ISP模块基础
ISP模块初始化总体流程:
A、Daemon进程调用server_process_module_sensor_init()函数对各模块进行初始化:
函数目录:vim vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server.c
int main(int argc __unused, char *argv[] __unused)
{
………………
/* 2. after open node, initialize modules */
if(server_process_module_init() == FALSE)
goto module_init_fail;
………………
}
B、遍历modules_list[]完成对各模块初始化:
函数目录:vim vendor/qcom/proprietary/mm-camera/mm-camera2/server-imaging/server_process.c
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},
};
boolean server_process_module_init(void)
{
………………
for (i = 1; i <(int)(sizeof(modules_list)/sizeof(mct_module_init_name_t)); i++)
…………………
}
C、调用ISP模块初始化入口函数module_isp_init()完成isp模块初始化:
函数目录:vim vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/isp2/module/isp_module.c
mct_module_t *module_isp_init(const char *name)
{
……………
/* Create MCT module for ISP */
module = mct_module_create(name);
/* Initialize isp pipeline */
ret = isp_resource_init(&isp->isp_resource);
/* Set isp private data */
MCT_OBJECT_PRIVATE(module) = (void *)isp;
/* Create ports */
ret = isp_port_create(module);
/* Overwrite module functions */
isp_module_overwrite_funcs(module);
……………
}
这个函数将创建ISP模块并返回其指针,另外将创建它的端口,填充一些功能函数等。它的主要执行流程如下:
C1.创建sensor的MCT module —— mct_module_create(name)
C2.初始化ISP pipeline和初始化子模块(包括bpc、bcc与snr) —— ret = isp_resource_init(&isp->isp_resource);
下面会具体分析,如何初始化子模块;
C3.设置private data —— MCT_OBJECT_PRIVATE(module) = (void *)isp;
C4. 创建端口 —— ret = isp_port_create(module);
ISP作为inter端口,需要创建source和sink端口;
C5. isp_module_overwrite_funcs(module);
填充set mode、query mode、start session、stop session和set session接口函数;
3.2 ISP模块总体初始化框图
3.3 ISP子模块bpc(Bad Pixel Correction)初始化流程及框图
以bpc子模块为例简要分析:
bpc子模块路径:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/isp2/hw/bpc/
以bpc40为例来分析该模块:
Note:该章节以code表示目录vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/isp2/hw/bpc/
A.打开Android.mk文件
vim code/bpc40/Android.mk
可以看到文件会编译为libmmcamera_isp_bpc40.so库文件,具体如何调用可以参考上一节ISP总体框图:
LOCAL_MODULE := libmmcamera_isp_bpc40
B.打开module_bpc40.c文件
vim code/bpc40/module_bpc40.c
static mct_module_t *module_bpc40_init(const char *name)
{
…………
module = isp_sub_module_init(name, NUM_SINK_PORTS, NUM_SOURCE_PORTS,
&bpc40_private_func, ISP_MOD_BPC, "bpc", ISP_LOG_BPC);
…………
}
B1.设置log level
isp_sub_module_util_setloglevel(mod_name, mod_id);
B2.创建mct module
module = mct_module_create(name);
B3.创建端口sink,source端口
ret = isp_sub_module_port_create(module, num_sink_ports, num_source_ports);
B4.填充接口函数
isp_sub_module_overwrite_funcs(module);
填充set mode、query mode、start session、stop session接口函数;
B5.填充mct module的private成员,即module->priv
isp_sub_module_priv->num_sink_ports = num_sink_ports;
isp_sub_module_priv->num_source_ports = num_source_ports;
//private_func中是每一个子模块特有的功能函数
isp_sub_module_priv->private_func = private_func;
isp_sub_module_priv->hw_module_id = hw_module_id;
isp_sub_module_priv->mod_id_for_log = mod_id;
strlcpy(isp_sub_module_priv->module_name, mod_name,
sizeof(isp_sub_module_priv->module_name));
MCT_OBJECT_PRIVATE(module) = (void *)isp_sub_module_priv;
C.框图