3. Camera HAL层核心数据结构详解
Camera HAL层是Android相机框架中连接Framework与底层硬件驱动的关键桥梁。理解其核心数据结构是进行HAL层开发与调试的基础。本章将详细剖析camera_module_t、camera_device_t、camera3_device_t、camera3_stream_t等关键结构体的定义、成员含义及相互关系。
3.1 结构体总览与层次关系
Camera HAL层的数据结构遵循从模块到设备、再到流和缓冲区的层次化设计。下图展示了核心结构体之间的调用与包含关系:
3.2 camera_module_t:模块级入口
camera_module_t是HAL模块的顶层结构体,定义在hardware/libhardware/include/hardware/camera_common.h中。它继承自hw_module_t,是Framework加载HAL库时首先获取的对象。
| 成员 | 类型 | 说明 |
|---|---|---|
| common | hw_module_t | 标准硬件模块结构体,包含模块ID、版本号、作者等信息 |
| get_number_of_cameras | 函数指针 | 返回系统中可用的Camera设备数量 |
| get_camera_info | 函数指针 | 获取指定Camera设备的静态信息(camera_info_t) |
| set_callbacks | 函数指针 | 注册HAL模块回调函数(HAL3特有) |
| get_vendor_tag_ops | 函数指针 | 获取厂商自定义标签操作接口 |
| open_legacy | 函数指针 | 以HAL1兼容模式打开Camera设备(可选) |
| set_torch_mode | 函数指针 | 设置闪光灯手电筒模式 |
| init | 函数指针 | 模块初始化函数(HAL3.4+) |
调试要点:当Camera HAL模块无法加载时,首先检查camera_module_t中的common.module_api_version是否正确。HAL3要求版本号至少为CAMERA_MODULE_API_VERSION_2_4。若版本不匹配,Framework将拒绝加载该模块。
3.3 camera_device_t:HAL1设备结构体
camera_device_t是HAL1架构下的设备结构体,定义在hardware/libhardware/include/hardware/camera.h中。它继承自hw_device_t,代表一个具体的Camera物理设备。
typedef struct camera_device {
hw_device_t common; // 标准硬件设备结构体
camera_device_ops_t *ops; // 设备操作函数指针表
void *priv; // 私有数据指针,指向HAL实现内部结构
} camera_device_t;
关键成员解析:
- common:包含设备打开/关闭、版本号等基础信息。
- ops:指向
camera_device_ops_t结构体,包含预览、拍照、参数设置等操作函数。 - priv:HAL实现者自定义的私有数据结构,通常包含设备状态、传感器信息等。
常见问题:在HAL1中,ops中的函数指针必须全部正确初始化,否则调用时会导致空指针异常。调试时建议在HAL实现中增加日志,打印ops各成员的地址,确保无NULL指针。
3.4 camera3_device_t:HAL3设备结构体
camera3_device_t是HAL3架构的核心设备结构体,定义在hardware/libhardware/include/hardware/camera3.h中。它替代了HAL1的camera_device_t,支持更灵活的请求-结果模型。
typedef struct camera3_device {
hw_device_t common; // 标准硬件设备结构体
camera3_device_ops_t *ops; // HAL3设备操作函数指针表
void *priv; // 私有数据指针
} camera3_device_t;
与camera_device_t的核心差异:
| 对比维度 | camera_device_t (HAL1) | camera3_device_t (HAL3) |
|---|---|---|
| 操作模型 | 同步调用,函数直接返回结果 | 异步请求-结果模型,通过回调返回 |
| 流管理 | 固定流配置,预览/拍照分离 | 动态流配置,支持多流并行 |
| 缓冲区管理 | HAL内部管理缓冲区 | Framework管理缓冲区,HAL通过dequeue/queue操作 |
| 元数据 | 使用camera_parm_t结构体 | 使用camera_metadata_t(基于key-value的元数据包) |
| 主要操作接口 | set_parm/get_parm/preview/take_picture | configure_streams/process_capture_request/flush |
开发建议:在HAL3实现中,camera3_device_ops_t包含initialize、configure_streams、process_capture_request、flush等关键函数。其中configure_streams是调试高频点,需确保返回的流配置与Framework请求一致。
3.5 camera3_stream_t:流描述结构体
camera3_stream_t是HAL3中描述图像流的核心结构体,定义在camera3.h中。它定义了流的格式、尺寸、方向等属性,是configure_streams和process_capture_request之间的数据契约。
typedef struct camera3_stream {
int stream_type; // 流类型:CAMERA3_STREAM_OUTPUT / INPUT / BIDIRECTIONAL
uint32_t width; // 图像宽度(像素)
uint32_t height; // 图像高度(像素)
int format; // 像素格式:HAL_PIXEL_FORMAT_xxx
uint32_t usage; // 图形缓冲区使用标志(GRALLOC_USAGE_xxx)
uint32_t max_buffers; // 最大缓冲区数量(由HAL设置)
void *priv; // 私有数据指针
android_dataspace_t data_space; // 数据空间(颜色空间、动态范围等)
int rotation; // 旋转角度:0/90/180/270
int stream_configuration; // 流配置类型(HAL3.3+)
const camera_metadata_t *physical_camera_id; // 物理Camera ID(多摄场景)
} camera3_stream_t;
流类型说明:
- CAMERA3_STREAM_OUTPUT:输出流,数据从Camera HAL流向Framework(预览、拍照、录像)。
- CAMERA3_STREAM_INPUT:输入流,数据从Framework流向Camera HAL(如YUV重处理)。
- CAMERA3_STREAM_BIDIRECTIONAL:双向流,支持输入和输出(如ZSL场景)。
调试要点:在configure_streams回调中,Framework会传入一个camera3_stream_t数组。HAL实现必须检查每个流的format和usage是否支持。若某个流不被支持,需返回-EINVAL并打印日志。常见不支持的格式包括HAL_PIXEL_FORMAT_RAW10(部分ISP不支持)和HAL_PIXEL_FORMAT_BLOB(JPEG输出)。
3.6 结构体协作流程:从配置到捕获
下图展示了HAL3中核心结构体在典型拍照流程中的协作关系:
3.7 常见调试问题与排查方法
| 问题现象 | 可能原因 | 排查方法 |
|---|---|---|
| HAL模块加载失败 | camera_module_t.common.module_api_version版本过低 |
检查版本号是否≥CAMERA_MODULE_API_VERSION_2_4 |
| configure_streams返回错误 | 流格式/尺寸不支持,或max_buffers设置不合理 |
打印所有流的format/width/height,对照ISP能力表 |
| 预览黑屏 | camera3_stream_t.usage缺少GRALLOC_USAGE_HW_COMPOSER标志 |
检查usage标志位,确保包含显示相关标志 |
| 拍照无JPEG输出 | JPEG流格式错误或data_space未正确设置 |
确认format为HAL_PIXEL_FORMAT_BLOB,data_space为HAL_DATASPACE_V0_JFIF |
| 多摄切换失败 | physical_camera_id未正确设置或与逻辑Camera不匹配 |
打印physical_camera_id,验证与底层传感器ID对应关系 |
调试工具推荐:使用adb shell dumpsys media.camera查看Camera服务状态,使用logcat -s CameraHal过滤HAL层日志。在HAL实现中增加ALOGD打印关键结构体成员值,是定位问题的最直接手段。
3.8 结构体内存布局与对齐注意事项
在嵌入式平台上,结构体的内存对齐可能影响跨进程通信和性能。以下为关键注意事项:
- 指针大小:
camera3_device_t中的ops和priv在32位平台占4字节,64位平台占8字节。跨架构编译时需注意。 - 结构体填充:
camera3_stream_t包含多个32位和64位成员,编译器可能插入填充字节。建议使用__attribute__((packed))或显式填充字段。 - 版本兼容:不同HAL版本的结构体成员可能不同。例如
camera3_stream_t在HAL3.3中新增了physical_camera_id字段。使用sizeof()检查结构体大小可快速判断版本。
// 检查结构体大小的调试代码示例
ALOGD("camera3_stream_t size: %zu", sizeof(camera3_stream_t));
ALOGD("camera3_device_t size: %zu", sizeof(camera3_device_t));
ALOGD("camera_module_t size: %zu", sizeof(camera_module_t));
重要提醒:在HAL实现中,切勿直接修改Framework传入的camera3_stream_t结构体成员(如width、format)。这些成员由Framework设置,HAL只能读取。若需要调整流参数,应在configure_streams中返回新的配置,或通过camera3_stream_configuration中的operation_mode字段协商。