3. Metadata数据结构:CameraMetadata类、vendor_tag_ops、Vendor Tag注册机制
Camera HAL 层与 Framework 之间的参数传递依赖一套标准化的元数据(Metadata)数据结构。Android 通过 CameraMetadata 类封装标准与厂商自定义参数,并借助 vendor_tag_ops 接口与 Vendor Tag 注册机制实现扩展。本章深入剖析这三者的设计原理与实现细节。
3.1 CameraMetadata 类:核心数据结构
CameraMetadata 是 Android Camera 框架中用于存储和传递参数的核心类,本质是一个键值对(Key-Value)容器。它封装了底层 camera_metadata_t 结构体,提供类型安全的读写接口。
3.1.1 内部存储结构
camera_metadata_t 采用紧凑的连续内存布局,包含以下部分:
| 字段 | 说明 | 字节对齐 |
|---|---|---|
| header | 元数据头部,包含版本号、条目数、总大小等 | 4 字节 |
| entries | 条目数组,每个条目包含 Tag ID、数据类型、计数、数据偏移 | 8 字节 |
| data | 实际数据存储区,按 8 字节对齐存放所有条目的值 | 8 字节 |
关键设计: 条目与数据分离存储,支持 O(1) 查找(通过 Tag ID 二分搜索),且数据区紧凑排列,减少内存碎片。
3.1.2 类型系统与访问接口
CameraMetadata 支持 8 种基本数据类型,每种类型对应一组 get/set 方法:
- BYTE (uint8_t) — 用于枚举、标志位
- INT32 (int32_t) — 整数参数
- FLOAT (float) — 浮点数参数
- INT64 (int64_t) — 时间戳、长整数
- DOUBLE (double) — 高精度浮点
- RATIONAL (int32_t num/den) — 分数,如曝光时间
- STRING (char*) — 字符串
- MULTI — 复合类型(如矩形、尺寸)
// CameraMetadata 典型用法示例
CameraMetadata metadata;
int32_t exposureTime = 100000; // 100ms
metadata.update(ANDROID_SENSOR_EXPOSURE_TIME, &exposureTime, 1);
// 读取
int32_t value = 0;
if (metadata.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
camera_metadata_entry_t entry;
metadata.find(ANDROID_SENSOR_EXPOSURE_TIME, &entry);
value = entry.data.i32[0];
}
3.2 vendor_tag_ops:厂商标签操作接口
Android 定义 vendor_tag_ops 结构体作为 HAL 层向 Framework 暴露自定义 Tag 的桥梁。该结构体包含一组函数指针,由 HAL 实现,Framework 在初始化时调用以获取厂商 Tag 的元信息。
3.2.1 结构体定义
typedef struct vendor_tag_ops {
int (*get_tag_count)(const struct vendor_tag_ops *ops);
void (*get_all_tags)(const struct vendor_tag_ops *ops,
uint32_t *tag_array);
const char* (*get_section_name)(const struct vendor_tag_ops *ops,
uint32_t tag);
const char* (*get_tag_name)(const struct vendor_tag_ops *ops,
uint32_t tag);
int (*get_tag_type)(const struct vendor_tag_ops *ops,
uint32_t tag);
} vendor_tag_ops_t;
3.2.2 接口职责
| 函数 | 返回值 | 说明 |
|---|---|---|
get_tag_count |
int | 返回厂商自定义 Tag 的总数 |
get_all_tags |
void | 填充所有 Tag ID 到调用者提供的数组中 |
get_section_name |
const char* | 返回 Tag 所属 Section 名称(如 "com.example") |
get_tag_name |
const char* | 返回 Tag 的简短名称(如 "myCustomParam") |
get_tag_type |
int | 返回 Tag 的数据类型(对应 camera_metadata_type_t 枚举) |
实现要点:
get_section_name 返回的字符串通常以 Java 包名风格命名(如 "com.qualcomm"),用于在 Framework 层生成唯一的 Vendor Tag 键名。所有字符串必须保持静态生命周期,不可在调用后释放。
3.3 Vendor Tag 注册机制
Vendor Tag 的注册分为 HAL 层实现与 Framework 层加载两个阶段。整个过程确保厂商自定义参数能够像标准 Tag 一样被上层应用和框架访问。
3.3.1 注册流程
- HAL 实现 vendor_tag_ops:在 HAL 模块中填充
vendor_tag_ops结构体,并实现所有回调函数。 - HAL 模块导出接口:通过
camera_module_t.common中的get_vendor_tag_ops函数指针暴露给 Framework。 - CameraService 加载:启动时调用
get_vendor_tag_ops获取 HAL 的vendor_tag_ops实例。 - 注册到 Metadata 系统:CameraService 遍历所有 Vendor Tag,将其元信息注册到全局的
gVendorTagDescriptor中。 - Framework 层映射:Java 层的
CameraMetadataNative通过 JNI 访问注册后的 Vendor Tag,生成对应的Key对象。
3.3.2 Tag ID 分配规则
Android Metadata 系统将 Tag ID 空间划分为标准区与厂商区:
| 范围 | 归属 | 示例 |
|---|---|---|
| 0x00000000 ~ 0x7FFFFFFF | Android 标准 Tag | ANDROID_SENSOR_EXPOSURE_TIME = 0x0000000E |
| 0x80000000 ~ 0xFFFFFFFF | 厂商自定义 Tag | VENDOR_SENSOR_MODE = 0x80000001 |
注意事项: 厂商 Tag ID 必须由 HAL 自行管理唯一性,Android 框架不保证跨厂商的 ID 不冲突。建议使用 Section 名称的哈希值作为 ID 生成依据,或维护静态映射表。
3.4 实战:自定义 Vendor Tag 示例
以下展示一个完整的 Vendor Tag 注册实现片段,包含 HAL 端实现与 Framework 端使用。
3.4.1 HAL 端实现
// vendor_tag_ops 实现
static int vendor_get_tag_count(const struct vendor_tag_ops *ops) {
return 2; // 自定义两个 Tag
}
static void vendor_get_all_tags(const struct vendor_tag_ops *ops,
uint32_t *tag_array) {
tag_array[0] = 0x80000001; // VENDOR_HDR_MODE
tag_array[1] = 0x80000002; // VENDOR_AI_SCENE
}
static const char* vendor_get_section_name(
const struct vendor_tag_ops *ops, uint32_t tag) {
return "com.example.camera";
}
static const char* vendor_get_tag_name(
const struct vendor_tag_ops *ops, uint32_t tag) {
switch (tag) {
case 0x80000001: return "hdrMode";
case 0x80000002: return "aiScene";
default: return NULL;
}
}
static int vendor_get_tag_type(
const struct vendor_tag_ops *ops, uint32_t tag) {
switch (tag) {
case 0x80000001: return TYPE_BYTE; // 枚举
case 0x80000002: return TYPE_INT32; // 场景 ID
default: return -1;
}
}
// 模块导出
static vendor_tag_ops_t g_vendor_ops = {
.get_tag_count = vendor_get_tag_count,
.get_all_tags = vendor_get_all_tags,
.get_section_name = vendor_get_section_name,
.get_tag_name = vendor_get_tag_name,
.get_tag_type = vendor_get_tag_type,
};
int camera_module_get_vendor_tag_ops(
const struct vendor_tag_ops **ops) {
*ops = &g_vendor_ops;
return 0;
}
3.4.2 Framework 层使用
// Java 层通过 Key 访问 Vendor Tag
CameraCharacteristics.Key<Byte> KEY_HDR_MODE =
new CameraCharacteristics.Key<>(
"com.example.camera.hdrMode", Byte.TYPE);
CameraCharacteristics.Key<Integer> KEY_AI_SCENE =
new CameraCharacteristics.Key<>(
"com.example.camera.aiScene", Integer.TYPE);
// 在应用中使用
CameraCharacteristics chars = cameraManager.getCameraCharacteristics(id);
Byte hdrMode = chars.get(KEY_HDR_MODE);
Integer aiScene = chars.get(KEY_AI_SCENE);
3.5 数据结构关系总览
3.6 常见问题与最佳实践
性能考量: Vendor Tag 的查找比标准 Tag 多一次间接跳转(通过 Registry 获取类型信息)。对于高频访问的 Vendor Tag,建议在 HAL 初始化时缓存其类型和偏移量,避免每次查找都遍历 Registry。
- Tag 命名冲突: 不同厂商使用相同 Section 名称可能导致冲突。建议 Section 名称包含公司域名(如 "com.qualcomm.camera")。
- 数据类型选择: 优先使用 BYTE/INT32 等基础类型,避免使用 STRING 类型(解析开销大)。
- 版本兼容: 新增 Vendor Tag 时需同步更新 HAL 版本号,Framework 根据版本号决定是否加载新 Tag。
- 调试手段: 使用
dumpsys media.camera查看已注册的 Vendor Tag 列表,验证注册是否成功。