抄的camera流程

高通新的camera驱动架构设计发生了一些变化,借用互联网上常用的一种结构,大致的原理如此:将camera的所有功能划分为不同的模块,让模块自己来决定自己的事情(高内聚,低耦合),模块需要有统一的接口和格式。模块中有端口,通过端口把模块连接起来,又把模块挂在总线上。每一个端口的连接就是一个流,把这些流用pipeline来管理。每次启动一个camera就创建一个会话,由这个会话来管理此camera的一切事物。对于每一个会话,模块是共享的,它可以是camera的硬件资源也可以是其它资源(如一些软件算法等资源)。

那么如何来定义这个模块的结构呢?
1.端口——端口属于模块,如果这个模块只有source端口,那么它就是一个src模块;如果只有sink端口就是sink模块,如果都有就是中间模块。没有端口的模块是不能连接到流中的,但他可以完成一些其他的功能,比如接收引擎的设置,报告事件到bus等。连接到流中的端口,也就是说流事件(set/get)主要通过端口来处理。而来自于引擎的(set/get)通过模块来处理,当然端口也可以把事件交给模块来处理。模块内部的端口可以通过模块来建立关系,也可以建立内部的连接,端口有关get/set process。
2.模块线程——每个模块可以有一个线程来处理模块的事情。一个线程对应一个队列,线程就是从队列中取出数据处理,然后应答回去。
3.总线回调——挡一个模块向总线注册时,总线向其提供一个回调函数,当模块有事件发生时,调用这个函数向bus发消息,然后总线把这个消息提交给管道,管道把这个消息顺着流发下去。
4.模块的get、set以及process。

管道、引擎与会话
管道有两端,一端用于读,一端用于写。camera引擎负责对管道的监控,而会话管理camera引擎。

从代码结构上来看这种新的驱动架构
高通的camera deamon代码放置在vendor\qcom\proprietary\mm-camera目录下,而此目录下的mm-camera2就是新的camera架构位置,进入里面可以看到media-controller、server-imaging、server-tuning及其它几个目录,我们这里需要关注的就是media-controller目录。

media-controller
|- mct——应该就是camera的引擎?里面包含了引擎、pipiline、bus、module、stream及event等定义及封装。
|- modules——这里面就是划分好的一些模块代码,各模块大致功能如下
|- sensor —— sensor 的驱动模块? ——src模块
|- iface —— ISP interface模块 ——inter模块
|- isp —— 主要是ISP的处理,其内部又包含了众多的模块 ——inter模块
|- stats —— 一些统计算法模块,如3A,ASD,AFD,IS,GRRO等数据统计的处理 ——sink模块
|- pproc —— post process处理 ——inter模块
|- imglib —— 主要是图片的一些后端处理,如HDR等 ——sink模块

以上各模块内部又包含了众多的模块,具体需要看代码分析。

 

高通camera daemon进程


1.概述
高通在Android的camera架构中,依旧沿用了其传统的方式,将其自身的一些处理放在一个daemon进程中。这部分内容出于应用于driver之间,是为了保护自身及硬件厂商的利益而专门弄出来的一个东东。其它各家平台也采用类似的方式将这部分的处理放在HAL层处理。

 

2.进程的入口
做为一个单独的进程,那肯定是有其main函数入口的。在vendor\qcom\proprietary\mm-camera\mm-camera2\server-imaging\server.c文件中可以看到这个main函数。在这个函数中主要做了以下几件事情。
1.找到服务节点的名字并打开此节点
get_server_node_name(serv_hal_node_name)
......
hal_fd->fd[0] = open(dev_name, O_RDWR | O_NONBLOCK); //这里dev_name为节点名如"/dev/serv_hal_node_name"
2.初始化模块。目前有sensor、iface、isp、stats、pproc及imglib六个模块(见笔记一)
server_process_module_init();
3.进入主循环来处理来自HAL及MCT的事件及消息,处理完之后的结果反馈给kernel(msm.c)
RD_FD_HAL
----> server_process_hal_event(&event)。此函数如果返回真,表示事件消息已经传给了MCT,这时不需要发送CMD ACK给kernel,因为MCT处理结束后会发出通知。如果返回假,表示没有传到MCT,此时需要立即发送CMD ACK到kernel,以便HAL发送此消息的线程阻塞住。
RD_DS_FD_HAL —— 通过domain socket传自HAL的消息
----> server_process_hal_ds_packet(fd_info->fd
RD_PIPE_FD_MCT —— 来自media controller的消息

media controller线程

1.概述
MCT线程是camera新架构的引擎部分,负责对管道的监控,由此来完成一个camera设备的控制运转。它运行在daemon进程空间,由MSM_CAMERA_NEW_SESSION事件来开启,具体开启函数为mct_controller_new()。

2.mct_controller_new()函数
此函数创建一个新的MCT引擎,这将对应一个事务的pipeline。我们知道上层可以创建多个事务,每个对应一个camera,也对应自己的MCT及pipeline等。因此这个函数的主要完成以下几件事情:
1.mct_pipeline_new()
---->创建一个Pipeline及其bus,并完成pipeline函数的映射。
2.mct_pipeline_start_session()
---->开启camera的所有模块并查询其能力
3.pthread_create(..., mct_controller_thread_run, ...)
---->创建mct线程并开始执行
4.pthread_create(..., mct_bus_handler_thread_run, ...)
---->创建bus处理线程

3.mct_list_traverse()函数
此函数在整个mct线程中大量使用,主要用来遍历所有模块并执行一些处理工作。结合前面所讲,camera各模块都具有统一的接口,通过流来连接,模块中又包含模块,根据这种特性高通使用链表结构来保存这些模块并设计了此函数用来完成遍历操作。
1.先来看看此链表的节点结构。链表的节点其实也是一个链表,整个链表就好像是一串串同级的节点搭建而成,整个数据结构组成一颗树结构。
struct _mct_list {

void *data; // 节点数据

mct_list_t *prev; // 上一个节点地址

mct_list_t **next;// 下一个节点节点元素数组首地址

uint32_t next_num; // 下一个节点节点元素数,大部分情况下为1
}mct_list_t;

2.通过递归的深度优先算法来遍历整棵树。

 

4.MCT线程运行

MCT整个引擎部分主要处理server及bus两类事情,对应前面提到的MCT及bus两个线程。MCT线程主要用来处理来自image server的消息,先pop MCT queue,查看是否有消息,如果有则执行mct_controller_proc_serv_msg_internal()函数来处理。

mct_controller_proc_serv_msg_internal函数用来处理来自image server的消息,并返回类型MCT_PROCESS_RET_SERVER_MSG。这里处理的消息类型主要有SERV_MSG_DS与SERV_MSG_HAL两种,分别在pipline中给出了相应的处理函数,具体查看源码可知。

 

5.bus线程运行

bus线程跟MCT线程流程一样。从代码上我们看到两个线程都是从同一个queue上面pop消息,他们是通过各自的线程条件变量来进行区分,完成线程的阻塞及运行工作。MCT的条件变量mctl_cond可以看到是在server_process.c文件中标记的,而bus的条件变量mctl_bus_handle_cond未在源码中找到标志的位置?

sensor模块

1.概述

sensor模块是众多模块中的一个,主要是由模组的各个硬件模块组成,包括sensor、Flash、Af、EEprom、OIS、CSI等。这个模块主要描述了模组硬件的一些工作原理及部分驱动相关部分。

 

2.module_sensor_init()函数

在前面讲到的server process中提到,服务进程开始后会初始化各个模块,其中就包括sensor模块,sensor初始化入口函数即为module_sensor_init(...)。这个函数将创建sensor模块并返回其指针,另外将创建它的端口,填充一些功能函数等。它的主要执行流程如下:

1.创建sensor的MCT module。 —— mct_module_create(name)

创建完之后填充set mode、query mode、start session、stop session及set session data五个接口函数。

2.创建module_sensro_ctrl_t结构体,此结构体包含bundle信息,用来构建前面提到的模块树(方便添加、遍历等操作)。

3.sensor模块是source模块,所以其numsinkports应该设置为0。

4.eebin相关的操作

5.sensor的探测操作,用来探测有效的sensor。

6.填入所有已探测到sensor的信息。

7.填入所以sensor的其它信息(Actuator,Flash,CSID,OIS等)。

8.初始化sensor模块。

9.创建基于CID info的端口

10.初始化eeprom

高通camera学习笔记五(actuator驱动参数解析)

1.概述

actuator驱动信息文件是指vendor目录下的$ActuatorName_actuator.h文件(如gigaset_actuator.h)。此信息文件就是一个actuator_driver_ctrl_t结构体。包括actuator_params与actuator_tuned_params两部分,即driver与tunning两部分。文档以目前最主流的VCM为例进行参数的介绍。

 

2.driver部分信息——actuator_params

act_type: actuator类型,目前就VCM、PIEZO及HVCM三种

data_size:数据长度(VCM指传输lens位置的数据长度?)

init_settings:actuator的初始化参数

reg_tbl:寄存器列表,用来下actuator移动参数,这些参数又包括如下一些参数选项

reg_write_type:写入数据的格式,VCM一般使用DAC,10位表示0~1023

reg_addr:写入数据寄存器地址,如果不需要具体地址,则配置为0xFFFF

data_shift:数据对应寄存器的移位

hw_mask:其它bit位的控制设置,比如VCM的ring_ctrl

hw_shift:控制设置对应寄存器的移位

reg_tbl部分举例AD5823如下:

.reg_tbl =

{

.reg_tbl_size = 1,

.reg_params =

{

{

.reg_write_type = MSM_ACTUATOR_WRITE_DAC,

.hw_mask = 0x00000400, 除data外的其它b it位的mask

.reg_addr = 0x04, //寄存器写地址为reg04

.hw_shift = 0, //hw_mask已经制定了明确的bit位,所以不再需要移位

.data_shift = 0, //reg05[7:0]为数据,所以不需要移位

},

},

},

查看驱动代码大致如下:

value = (next_lens_position <<

write_arr[i].data_shift) |

((hw_dword & write_arr[i].hw_mask) >>

write_arr[i].hw_shift);

最终获得I2C数据代码如下:

i2c_byte1 = (value & 0xFF00) >> 8; //对应reg04寄存器值

i2c_byte2 = value & 0xFF; //对应reg05寄存器值

这里获得的value及需要写入寄存器的值,上面的hw_dword参数来自于tunning参数表中的hw_params (此驱动的hw_params值为0x00000400)。下面再来看看AD5823的寄存器介绍:

 

上图中reg04的bit[3]设置是否开启RING_CTRL模式,bit[7:4]为零,由前面讲到的hw_dword及hw_mask来设置。

再举例DW9714如下:

.reg_params =

{

{

.reg_write_type = MSM_ACTUATOR_WRITE_DAC,

.hw_mask = 0x0000000F, //除data外的其它b it位的mask

.reg_addr = 0xFFFF, //没有寄存器地址

.hw_shift = 0, //hw_mask已经制定了明确的bit位,不再需要移位

.data_shift = 4, //10bit的数据移位

},

},

再看DW9714规格书寄存器介绍如下:

 

与代码对比可以看出,byte2的S[3:0]对应给出了mask位,需要根据tunning参数的hw_dword来确定具体的模式,此驱动给出的tunning参数为0x00000004,即S[3:0]-0100;而PD及FLAG被设置为0。

 

3. tunning部分——actuator_tuned_params

tunning参数分为向近景方向移动与向远景方向移动两部分(MOVE_NEAR&MOVE_FAR),每个部分又可设定多个移动场景,各个场景参数可以单独设定,以便实现更细化的控制。

高通在这里实现了一个lens位置数组,数组中的具体值对应着实际的lens位置,所以在驱动中可以看到step_pos与lens_pos两个参数,分别对应词数组表的下标index及当前index对应的值(此值为lens的实际位置)。代码体现如下:

curr_lens_pos = a_ctrl->step_position_table[a_ctrl->curr_step_pos];

具体一些参数介绍如下:

initial_code:初始lens的位置,对应VCM的0~1023的范围

scenario_size:向近景与远景方向移动部分的场景数

ringing_scenario: 各对应场景向近景与远景方向的移动步数最大值

region_size:对lens的移动进行多个区段划分,可实现更细化的设置(针对非线性?)

region_params:对应每个区段的在移动步数表中的index范围,即bound

step_bound:对应具体的macro及infinity的bound边界值,所有区段合起来就是总 长度(对应上面提到的表的长度)

code_per_step:在当前分区中每个step对应移动的实际lens长度

上面这些参数一起最终声场移动步数表数组,具体在msm_actuator_init_step_table函数中实现,具体可查看代码(msm_actuator.c文件),关键语句:

cur_code = set_info->af_tuning_params.initial_code; //初始值

code_per_step =a_ctrl->region_params[region_index].code_per_step; //当前分区的步长

cur_code += code_per_step; //每步叠加一个步长

damping:这部分参数用来做刹车消除磁滞,与前面的场景参数相呼应。

ringing_params:各个具体场景对应的参数设置。下面三个参数为当前场景各区段的参数设置。

damping_step: // 对应场景lens每次移动的最大步长

damping_delay: // 对应场景lens每次移动I2C命令间的延时

hw_params: // 对应场景actuator硬件寄存器的控制设置

 

上面写了那么多,总结起来也就下面几点:

1.有一个数组lens_pos[max_bound] -----> 对应前面多次提到的移动步数数组

2.为了更好的消除磁滞,设定了多种移动的规则,根据每次移动的最大step来确定使用哪个规则---->规则即前面讲的场景,最大step就是前面的ringing_scenario数组中对应每个场景的值,这个值表示数组的下标。

3.将整个移动范围分成多个区间,细分每个区间lens步进,针对线性化问题改善。

4.针对不同场景的不同区间设定磁滞消除参数。

另外要注意的一点是高通AF算法发出的参数为step数量,而不是具体的lens位置,具体lens位置需要查表获得。其实从这部分参数设定来看可以发现这里主要对驱动芯片的驱动方式进行设定,算法上前进步长的判断还是在其它地方实现,只要控制了每次的step长度,也就相当于进行了磁滞控制,所以参数damping_step设置为最大值是可以理解的。

下面举例来说明一下:

.actuator_tuned_params =

{

.scenario_size =

{

1, /* MOVE_NEAR */ //场景数量,这里就定义了一个场景

1, /* MOVE_FAR */

},

.ringing_scenario =

{

/* MOVE_NEAR */

{

400, //对应场景最大步子,移动步数小于此值表示适用此场景参数。这里只定义了一个场景,所以将此值设置为最大步数(即数组容量)。此值表示每次移动步数的步子大小判断,不是具体的数组下标。

},

/* MOVE_FAR */

{

400,

},

},

.initial_code = 70, //初始lens的位置

.region_size = 1, //对lens的移动进行多个区段划分,用于不同区间磁滞的参数设定

.region_params =

{

{

.step_bound = //对应每个区段的step bound,这里只定义了一个区间,即整个VCM移动过程使用同样的磁滞处理。

{

400, /* Macro step boundary*/ //当前区段的结束step

0, /* Infinity step boundary*/ //当前区段的起始step

},

.code_per_step = 1, // step表中lens的步进长度

},

},

.damping =

{

/* damping[MOVE_NEAR] */

{

/* Scenario 0 */ //当前场景的磁滞参数

{

.ringing_params =

{

/* Region 0 */ //当前区间的磁滞参数

{

.damping_step = 0x3FF, //这里设置为最大值1023,相当于不做磁滞处理,直接一次设定到需要的值。

.damping_delay = 6000,

.hw_params = 0x00000000,

},

},

},

},

/* damping[MOVE_NEAR] */

{

/* Scenario 0 */

{

.ringing_params =

{

/* Region 0 */

{

.damping_step = 0x3FF,

.damping_delay = 6000,

.hw_params = 0x00000000,

},

},

},

},

},

}, /* actuator_tuned_params */

Camera启动篇一

主要记录一下启动的过程,顺便看看是否能把握到数据流的走向,这次以高通810平台Android5.1为蓝本。本篇主要讲述Framework及Hardware部分,涉及到JAVA及driver部分的如有必要也会捎带提及一下。

一、启动Camera在JAVA层开始,主要是启动了一个OpenCameraThread的线程(PhotoModule.java),代码如下:

?
1
2
3
4
1 if (mOpenCameraThread == null && !mActivity.mIsModuleSwitchInProgress) {
2             mOpenCameraThread = new OpenCameraThread();
3             mOpenCameraThread.start();
4         }

在这个线程中只做了两件事情,整个Camera的启动过程也是围绕着他们展开的:

?
1
2
3
4
5
6
7
1     private class OpenCameraThread extends Thread {
2         @Override
3         public void run() {
4             openCamera();      // 第一步开启camera
5             startPreview();    // 第二部开始preview
6         }
7     }

二、开启第一步openCamera

1. 还是在Java层,openCamera主要干了下面这些事情:

1.1CameraUtility.openCamera ------->重点部分

1.2 getParameters ------->一些参数获得

1.3 initializeFocusManager -------->Focus管理

1.4 initializeCapabilities -------->Camera选择的一些特性

1.5 sendMSG--CAMERA_OPEN_DONE -------->Open完成之后的处理

2. 上面那么多,我们只需要关注第一点就可以了,现在继续往下查看。关于这部分网上也有不少资料,可自行查看,直接查看源代码也比较清晰。总之在Camera开启成功后Java层会获得一个mCameraDevice,这个其实就是Camera的一个代理--AndroidCameraProxyImpl,当然我们要关注的是前面开启的过程。

?
1
2
3
4
5
6
7
8
9
10
11
12
1     public CameraManager.CameraProxy cameraOpen(
  2         Handler handler, int cameraId, CameraOpenErrorCallback callback) {
  3         mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0 ,
  4                 CameraOpenErrorCallbackForward.getNewInstance(
  5                         handler, callback)).sendToTarget();
  6         mCameraHandler.waitDone();
  7         if (mCamera != null ) {
  8             return new AndroidCameraProxyImpl();  // ----->这个就是丢给前台的mCameraDevice
  9         } else {
10             return null ;
11         }
12     }

3. OPEN_CAMERA的处理先使用传统的方式开启,如果不行再尝试新的open方式,这里开始就转到frameworks。frameworks基本没做什么东西,就是一个传话筒而已,很快就到了JNI。

?
1
2
3
4
5
6
7
8
9
10
11
12
1         public void handleMessage( final Message msg) {
  2             try {
  3                 switch (msg.what) {
  4                     case OPEN_CAMERA:
  5                         try {
  6                             mCamera = android.hardware.Camera.openLegacy(msg.arg1,     // 这里的android.hardware.Camera就指向frameworks\base\core\java\android\hardware\camera.java
  7                                     android.hardware.Camera.CAMERA_HAL_API_VERSION_1_0);  // 先使用传统的接口打开
  8                         } catch (RuntimeException e) {
  9                             /* Retry with open if openLegacy fails */
10                             Log.v(TAG, "openLegacy failed. Using open instead" );
11                             mCamera = android.hardware.Camera.open(msg.arg1); //若出现异常再使用新的接口打开,这里提供两种方式也是方便硬件厂商做兼容及区别处理,到现在的AndroidM版本,Camera HAL已经有了3个版本了,但高通810目前还是使用HAL1
12                         }

4. openLegacy的JNI调用为native_setup。JNI调用将转到android_hardware_Camera.cpp文件,关于这部分网上也有很多资料。其实这里也没干什么事情,跟frameworks一样,都只是一个传递的作用,整个Camera框架真正有内涵的还是HAL以及driver部分,当然APP部分的各种呈现也很有内涵。

1returnnative_setup(newWeakReference(this), cameraId, halVersion, packageName);

这里通过JNI到了C++层

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1 // connect to camera service
  2 static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
  3     jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
  4 {
     。。。。。。 10     //ALOGV("native setup: halversion %d", halVersion);//native setup: halversion 256
11     sp<camera> camera;
12     if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {  //CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2
13         // Default path: hal version is don't care, do normal camera connect.
14         camera = Camera::connect(cameraId, clientName,
15                 Camera::USE_CALLING_UID);
16     } else {
17         jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
18                 Camera::USE_CALLING_UID, camera);
19         if (status != NO_ERROR) {
20             return status;
21         }</camera>

调用到Camera的connectLegacy

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1 status_t Camera::connectLegacy( int cameraId, int halVersion,
  2         const String16& clientPackageName,
  3         int clientUid,
  4         sp<camera>& camera)    // 需返回的Camera设备
  5 {
  6     ALOGV( "connectLegacy: connect legacy camera device,halVersion %d" , halVersion);
  7     sp<camera> c = new Camera(cameraId);
  8     sp<icameraclient> cl = c;      // 这个示例很重要,CameraService将包含此示例,用来执行回调调用到Client这边。
  9     status_t status = NO_ERROR;
10     const sp<icameraservice>& cs = CameraBaseT::getCameraService();   // 获取CameraService
11
12     if (cs != 0 ) {
13         status = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName,   // 调用CameraService的connectLegacy
14                                         clientUid, /*out*/ c->mCamera);
15     }
16     if (status == OK && c->mCamera != 0 ) {
17         c->mCamera->asBinder()->linkToDeath(c);
18         c->mStatus = NO_ERROR;
19         camera = c;
20     } else {
21         ALOGW( "An error occurred while connecting to camera: %d" , cameraId);
22         c.clear();
23     }
24     return status;
25 }</icameraservice></icameraclient></camera></camera>

这部分有太多的资料阐述,毕竟还是Android通用代码,未涉及到硬件芯片厂商的差异性。简约一些,connect会获得一个CameraService,这个Service将进行HAL层设备的管理及交互。我们跳转到CameraService::connectLegacy可以看到在这个Service中包含了一个CameraClient,而上面说到的返回的Camera设备就是这个Client(源码:device = client;)。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1 status_t CameraService::connectLegacy(
  2         const sp<icameraclient>& cameraClient,
  3         int cameraId, int halVersion,
  4         const String16& clientPackageName,
  5         int clientUid,
  6         /*out*/
  7         sp<icamera>& device) { // go here
  8
  9  。。。。。。
10
11     status_t status = validateConnect(cameraId, /*inout*/ clientUid);
12     if (status != OK) {
13         return status;
14     }
15
16     sp<client> client;
17     {
18         sp<basicclient> clientTmp;
19         Mutex::Autolock lock(mServiceLock);
20         if (!canConnectUnsafe(cameraId, clientPackageName,
21                               cameraClient->asBinder(),
22                               /*out*/ clientTmp)) {
23             return -EBUSY;
24         } else if (client.get() != NULL) {
25             device = static_cast<client*>(clientTmp.get());
26             return OK;
27         }
28
29         status = connectHelperLocked( /*out*/ client,   // 这个client就是上面调用中要返回的Camera设备device
30                                      cameraClient,    // 传下来的ICameraClient实例
31                                      cameraId,
32                                      clientPackageName,
33                                      clientUid,
34                                      callingPid,
35                                      halVersion,
36                                      /*legacyMode*/ true );
37         if (status != OK) {
38             return status;
39         }
40
41     }
42     // important: release the mutex here so the client can call back
43     //    into the service from its destructor (can be at the end of the call)
44
45     device = client;   // 返回的Client设备
46     return OK;
47 }</client*></basicclient></client></icamera></icameraclient>

在connectHelperLocked中,将根据不同HAL版本实现不同的示例,目前有CameraClient和Camera2Client两种

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1           case CAMERA_DEVICE_API_VERSION_1_0:
  2             ALOGV( "create a camera client.line %d" ,__LINE__);
  3             client = new CameraClient( this , cameraClient,      // 前面那个CameraClient是要实现的Client,第二个cameraClient就是上面传下来的ICameraClient实例
  4                     clientPackageName, cameraId,
  5                     facing, callingPid, clientUid, getpid(), legacyMode);
  6             break ;
  7           case CAMERA_DEVICE_API_VERSION_2_0:
  8           case CAMERA_DEVICE_API_VERSION_2_1:
  9           case CAMERA_DEVICE_API_VERSION_3_0:
10           case CAMERA_DEVICE_API_VERSION_3_1:
11           case CAMERA_DEVICE_API_VERSION_3_2:
12             ALOGI( "create a camera2 client" );
13             client = new Camera2Client( this , cameraClient,
14                     clientPackageName, cameraId,
15                     facing, callingPid, clientUid, getpid(), legacyMode);
16             break ;

上面获得Client后会调用connectFinishUnsafe(client,client->getRemote()),这个函数将会执行到HAL的interface,所以厂家通用。

?
1
2
3
4
5
1 status_t CameraService::connectFinishUnsafe( const sp<basicclient>& client,
2                                             const sp<ibinder>& remoteCallback) {
3     status_t status = client->initialize(mModule); //这个mModule很关键,是在CameraService.cpp中onFirstRef中获取的。其实就是根据类名等规则加载一个动态库,一般在/system/lib/hw/目录下,如camera.msm8994.so
 
4     if (status != OK) {</ibinder></basicclient>
?
1
2
3
4
5
6
7
8
9
5         ALOGE( "%s: Could not initialize client from HAL module." , __FUNCTION__);
  6         return status;
  7     }
  8     if (remoteCallback != NULL) {
  9         remoteCallback->linkToDeath( this );
10     }
11
12     return OK;
13 }

上面client中的initialize会调用到hardware interface中的initialize并设置callback (CameraHardwareInterface.h),而在这里就会调用到具体厂家HAL层的函数了。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1     status_t initialize(hw_module_t *module)
  2     {
  3         ALOGI( "Opening camera %s" , mName.string());
  4         camera_module_t *cameraModule = reinterpret_cast<camera_module_t>(module);
  5         camera_info info;
  6         status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
  7         if (res != OK) return res;
  8         ALOGI( "init hal-ver:%d,dev-ver %d" ,module->module_api_version,info.device_version); // 515=v2.3,770=v3.2
  9         int rc = OK;
10         if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
11             info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {ALOGI( "open legacy" );
12             // Open higher version camera device as HAL1.0 device.
13             rc = cameraModule->open_legacy(module, mName.string(),  // 这个cameraModule就上具体厂家代码编译出来的so库,这里对应QCamera2Factory.cpp
14                                                CAMERA_DEVICE_API_VERSION_1_0,
15                                                (hw_device_t **)&mDevice);
16         } else {
17             rc = CameraService::filterOpenErrorCode(module->methods->open(
18                 module, mName.string(), (hw_device_t **)&mDevice));
19         }
20         if (rc != OK) {
21             ALOGE( "Could not open camera %s: %d" , mName.string(), rc);
22             return rc;
23         }
24         initHalPreviewWindow();
25         return rc;
26     }</camera_module_t>

5.到这里就正式进入HAL层,每个厂家的实现代码也变得不一样,但大致模式还是差不多,都是通过V4L2的命令接口来控制具体的Camera设备。 HAL及driver将在另一篇继续讨论。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值