本文主要介绍展锐平台AndroidP camera hal代码框架,后续会有preview相关流程
1. 代码架构
先来看看主要的代码架构
app及framework为标准的Android hal3架构
主要涉及的文件及其调用关系如下图:
Camera HAL 层架构主要由以下几部分构成:
- SPRD Camera HAL Interface(SprdCamera3HWI): 实现 camera framework的调用接口。
- SPRD Camera OEM(SprdCamera3OEMIf): 连接 camera HWI 与底层。
- CMR_OEM:负责 OEM 层的控制以及对底层控制文件的调度
oem 提供了展讯平台 camera 功能的具体实现,包括队列,线程,和状态的相关实现.camera 功能包括 init,deinit,preview,take picture 等;硬件驱动的控制接口;isp 的算法实现,包括 awb,ae 等.包括SprdOEMCamera,cmr_oem,cmr_preview 等文件.
OEM 层的主要文件在 libcamera/oem 目录下。
- SprdOEMCamera:Camera OEM 模块的接口文件,用来向各种 Camera HAL 层文件提供统一的调用接口。
- cmr_oem:Camera OEM 模块的控制文件,用来控制其它模块,而其它模块
的交互也是通过该文件来完成。 - cmr_sensor:OEM 层 sensor 模块,向其它模块提供 sensor 模块的操作控制接口,处理 sensor 的流程控制。
- sensor_drv_u :位 于 user 层 sensor 驱动 的抽象接 口文件 ,它直 接操作
位于 kernel 的 sensor driver,向 cmr_sensor 和位于 user 层的 sensor driver文件提供统一的操作接口。 - cmr_ipm:OEM 层 ipm 模块,ipm 模块主要是一种图像后处理模块,主要处理第三方的图像处理库,如 Face Detect、 HDR 等等,希望通过本模块实现对外接口的一致,并有利于扩展。
- cmr_setting:OEM 层 setting 模块,setting 模块主要处理与 Camera HAL层交互的参数,为 Camera OEM 模块提供一组 set/get 函数接口以用来处理相关的 hal 参数。
- cmr_focus:OEM 层 focus 模块,focus 模块主要处理 AF 的相关操作,并将AF 的结果返回给其它模块。
- jpeg_codec:OEM 层 jpeg codec 模块的接口文件,该模块为其他模块提供了一组 jpeg 编解码功能的接口文件,用以完成拍照 JPEG 编码的操作。
- cmr_grab : OEM 层 grab 模 块 , 该 模 块 调 用 sprd image driver 相 关接 口 , 用 来 管 理 DCAM 硬件设备,包含设备通道的配置、 模式的设置、 启动、停止以及数据的读写等功能
- cmr_scaler:OEM 层 scaler 模块,该模块用来对一帧 buffer 做 scaler 图像后处理操作,管理 scaler 硬件设备。
- cmr_rotate:OEM 层 rotate 模块,该模块用来对一帧 buffer 做 rotate 图像后处理操作,管理 rotate 硬件设备。
- cmr_preview:OEM 层 preview 模块,该模块用来为 Camera 提供preview 子服务,包含 preview 流程的控制、 通道参数的配置、 接收 Camera OEM 模块设置的 buffer 给 grab 模块,接收底层返回的 buffer 数据并回调给Camera OEM 模块。
- cmr_snapshot:OEM 层 snapshot 模块,该模块用来为 Camera 提供拍照后处理操作,它接收图像数据并调用相关模块完成需要的图像后处理及 JPEG编码操作,并生成一个完成的 JPEG 图片返回给 Camera OEM 模块
Driver
主要实现了对 dcam 等硬件功能的实现,具体实现通过中断控制,线程调度.对相关多媒体子系统设置并控制
2. hal层接口
熟悉hal层的应该了解硬件抽象层模块结构体定义规范
相关结构体在 hardware/libhardware/include/hardware/hardware.h 中。
typedef struct hw_module_t {
uint32_t tag; //标签必须初始化为HARDWARE_MODULE_TAG
uint16_t module_api_version; //版本号
#define version_major module_api_version //version major
uint16_t hal_api_version;
#define version_minor hal_api_version //version minor
const char *id; //module 的 id
const char *name; //module 的 name
const char *author; // Author\/owner\/implementor of the module( 实现该模块)
struct hw_module_methods_t\* methods; //模块操作方法void* dso; //module's dso
#ifdef __LP64__
uint64_t reserved[32-7];
#else
uint32_t reserved[32-7]; /** padding to 128 bytes, reserved for future use
*/
#endif
} hw_module_t;
这个结构体使用的时间需要注意的是:
硬件抽象层中的每一个模块都必须自定义一个硬件抽象层模块结构体, 而且它的第一个成员变量的类型必须为 hw_module_t。硬件抽象层中的每一个模块都必须存在一个导出符号HAL_MODULE_INFO_SYM, 即“HWI” , 它指向一个自定义的硬件抽象层模块结构体。
a、 hal_module_info 的名字
#define HAL_MODULE_INFO_SYM HMI
b、 作为一个字符串的 hal_module_info 名称
#define HAL_MODULE_INFO_SYM_AS_STR “HMI”
结构体 hw_module_t 的成员变量 tag 的值必须设置为HARDWARE_MODULE_TAG。 用来标志这是一个硬件抽象层模块结构体。结构体 hw_module_t 的成员变量 dso 用来保存加载硬件抽象层模块后得到的句柄值, 加载硬件抽象层模块的过程实际就是调用 dlopen 函数来加载与其对应的动态链接库文件的过程。 在调用 dlclose 函数来卸载这个这个硬件抽象层模块时, 要用到这个句柄值, 因此, 我们在加载时需要将它保存起来。结构体 hw_module_t 的成员变量 methods 定义了一个硬件抽象层模块的操作方法列表, 它的类型为 hw_module_methods_t,它是用于定义操作设备的方法 operations。 它的定义如下:
typedef struct hw_module_methods_t {
int (*open)(const struct hw_module_t* module, const char* id,
struct hw_device_t** device); /** Open a specific device( 打开特定的
设备) */
} hw_module_methods_t;
结构体 hw_module_methods_t 只有一个成员变量, 它是一个函数指针, 用来
打开硬件抽象层模块中的硬件设备。 其中 module 表示要打开的硬件设备所在
的模块; 参数 id 表示要打开设备的 id, 参数 device 是一个输出参数, 用来
描述一个已经打开的硬件设备。 由于一个硬件抽象层模块可能会包含多个硬件
设备, 因此, 在调用结构体 hw_module_methods_t 的成员变量 open 来打开
一个硬件设备时, 我们需要指定她的 ID。 硬件抽象层中的硬件设备使用结构
体 hw_device_t 来描述。
typedef struct hw_device_t {
uint32_t tag; //标记 HARDWARE_DEVICE_TAG
uint32_t version; //版本号
struct hw_module_t* module; //该设备( 硬件) 属于哪个 module
#ifdef __LP64__
uint64_t reserved[12]; //预留字段, 将来使用#else
uint32_t reserved[12]; //预留字段, 将来使用
#endif
int (*close)(struct hw_device_t* device); //关闭该设备操作
} hw_device_t;
需要注意的是:
硬件抽象层模块中的每一个硬件设备都必须自定义一个硬件设备结构体, 而且
它的第一个成员变量的类型必须为 hw_device_t。
结构体 hw_device_t 的成员变量 tag 的值必须初始化为HARDWARE_DEVICE_TAG。结构体 hw_device_t 的成员变量 close 是一个函数指针, 它用来关闭一个硬件设备。
camera 的硬件抽象层接口。
位置: hardware/libhardware/include/hardware/camera_common.h
/**
* The id of this module
*/
#define CAMERA_HARDWARE_MODULE_ID "camera"
typedef struct camera_module {
hw_module_t common;
int (*get_number_of_cameras)(void);
int (*get_camera_info)(int camera_id, struct camera_info *info);int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
int (*open_legacy)(const struct hw_module_t* module, const char* id,
uint32_t halVersion, struct hw_device_t** device);
int (*set_torch_mode)(const char* camera_id, bool enabled);
int (*init)();
void* reserved[5];
} camera_module_t;
位置: hardware/libhardware/include/hardware/camera3
typedef struct camera3_device {
/ * Camera open (common.module->common.methods->open) should
return in */
hw_device_t common;
camera3_device_ops_t *ops;
void *priv;
} camera3_device_t;
定义一个模块操作方法
struct hw_module_methods_t SprdCamera3Factory::mModuleMethods = {
.open = SprdCamera3Factory::camera_device_open,
};
camera_device_open 会根据传进来的 ID 判断打开哪一个硬件设备。
typedef struct camera3_device_ops {
int (*initialize)(const struct camera3_device *,const camera3_callback_ops_t *callback_ops);
int (*configure_streams)(const struct camera3_device *,camera3_stream_configuration_t *stream_list);
int (*register_stream_buffers)(const struct camera3_device *,const camera3_stream_buffer_set_t *buffer_set);
int (*process_capture_request)(const struct camera3_device *,camera3_capture_request_t *request);
void (*get_metadata_vendor_tag_ops)(const struct camera3_device*,vendor_tag_query_ops_t* ops);
void (*dump)(const struct camera3_device *, int fd);
int (*flush)(const struct camera3_device *);
/* reserved for future use */
void *reserved[8];
}camera3_device_ops_t;
在经过上面的方法之后得到 camera3_device_ops_t , 上层会调用其中的initialize, 把 framework 层的回调函数 camera3_callback_ops_t 传至底层,底层获取数据时调用里面的两个方法。 这个调用在每次执行一个新的操作的时间会执行一次, 比如开始的时间是正常的 preview, 然后切换到 video,着时间就会调用这个方法;然后上层会调用 configure_streams 方法, 配置流, 因为每种操作所需要的参数可能都是不同的, 所以这个方法在每执行一个动作的时间都会调用;最后就是调用 process_capture_request 去将数据下发并开始动作;所以总结下来 framework 对 hal 层进行操作过程可以简单的理解为initialize->configure_streams-> process_capture_request。
typedef struct camera3_callback_ops {
void (*process_capture_result)(const struct camera3_callback_ops *,
const camera3_capture_result_t *result);
void (*notify)(const struct camera3_callback_ops *,
const camera3_notify_msg_t *msg);
}camera3_callback_ops_t;
下面是 ops 所对应的方法。
camera3_device_ops_t SprdCamera3HWI::mCameraOps = {
initialize: SprdCamera3HWI::initialize,
configure_streams: SprdCamera3HWI::configure_streams,
register_stream_buffers: NULL,//SprdCamera3HWI::register_stream_buffers,
construct_default_request_settings:SprdCamera3HWI::construct_default_request_settings,
process_capture_request:
SprdCamera3HWI::process_capture_request,
get_metadata_vendor_tag_ops:
NULL,//SprdCamera3HWI::get_metadata_vendor_tag_ops,
dump: SprdCamera3HWI::dump,
flush: SprdCamera3HWI::flush,reserved:{0},
};
SprdCamera3Hal.cpp 是 hal 层提供给 framework 的接口。
camera_module_t HAL_MODULE_INFO_SYM = {
common: camera_common,
get_number_of_cameras: sprdcamera::SprdCamera3Factory::get_number_of_cameras,
get_camera_info: sprdcamera::SprdCamera3Factory::get_camera_info,
set_callbacks: sprdcamera::SprdCamera3Factory::set_callbacks,/*HAL3.2*/
get_vendor_tag_ops: sprdcamera::SprdCamera3Factory::get_vendor_tag_ops,/*HAL 3.2 主
要是将 setting 里面的数据回传*/
open_legacy :0,/*HAL1.0*/
set_torch_mode: sprdcamera::SprdCamera3Factory::setTorchMode,
};
static hw_module_t camera_common = {
tag: HARDWARE_MODULE_TAG,
module_api_version: CAMERA_MODULE_API_VERSION_2_4,//CAMERA_MODULE_API_VERSION_2_0,
hal_api_version: HARDWARE_HAL_API_VERSION,
id: CAMERA_HARDWARE_MODULE_ID,
name: "Sprd Camera HAL3",
author: "Spreadtrum Corporation",
methods: &sprdcamera::SprdCamera3Factory::mModuleMethods,
dso: NULL,
reserved: {0},
};
在 frameworks/av/services/camera/libcameraservice 下面的
CameraService.cpp 里面。
void CameraService::onFirstRef()
{
camera_module_t *rawModule; //定义这个模块的指针对象
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID, (const hw_module_t **)&rawModule); //获得这个模块的 ID, 在上面的结构体可以看到, 在 HAL 层里面的 ID 就是这个。 通过 hw_get_module这个函数也就获取到了 HAL 层的接口。
mModule = new CameraModule(rawModule); //获得这个模块里面的方法
err = mModule->init();
} 然后调用 hardware/libhardware 下面的 hardware.c 里面的 hw_get_module方法。
int hw_get_module(const char *id, const struct hw_module_t **module)
{
return hw_get_module_by_class(id, NULL, module);
}
int hw_get_module_by_class(const char *class_id, const char *inst,
const struct hw_module_t **module)
{
return load(class_id, path, module);
}
Load 应该就会获取下面这个结构体里面的 ID。 这个是在 HAL 层里面的。
static hw_module_t camera_common = {
tag: HARDWARE_MODULE_TAG,
id: CAMERA_HARDWARE_MODULE_ID,
methods: &sprdcamera::SprdCamera3Factory::mModuleMethods,
};
struct hw_module_methods_t SprdCamera3Factory::mModuleMethods = {
open: SprdCamera3Factory::camera_device_open,
}; 然后就可以开始执行 HAL 层的 opencamera 和 request 的下发。