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 注册流程

  1. HAL 实现 vendor_tag_ops:在 HAL 模块中填充 vendor_tag_ops 结构体,并实现所有回调函数。
  2. HAL 模块导出接口:通过 camera_module_t.common 中的 get_vendor_tag_ops 函数指针暴露给 Framework。
  3. CameraService 加载:启动时调用 get_vendor_tag_ops 获取 HAL 的 vendor_tag_ops 实例。
  4. 注册到 Metadata 系统:CameraService 遍历所有 Vendor Tag,将其元信息注册到全局的 gVendorTagDescriptor 中。
  5. Framework 层映射:Java 层的 CameraMetadataNative 通过 JNI 访问注册后的 Vendor Tag,生成对应的 Key 对象。
Vendor Tag 注册流程 HAL 实现 vendor_tag_ops 导出 get_vendor_tag_ops CameraService 加载 注册到 Metadata 系统 Framework 层映射 应用层使用 Key 注册关键点: • Tag ID 必须在 0x80000000 ~ 0xFFFFFFFF 范围内(高位为 1 表示 Vendor Tag) • Section 名称用于生成 Java 层的 Key 类(如 CameraCharacteristics.Key<>) • 注册后不可动态修改,需重启 CameraService 才能生效

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 数据结构关系总览

Metadata 数据结构关系图 CameraMetadata 封装 camera_metadata_t vendor_tag_ops HAL 回调接口 Vendor Tag Registry 全局注册表 标准 Tag 条目 厂商 Tag 条目 Tag 元信息缓存 CameraMetadata 是数据容器,vendor_tag_ops 是注册接口,Vendor Tag Registry 是运行时元信息缓存。 三者协作实现:标准 Tag 直接访问数据区,Vendor Tag 通过 Registry 查询类型后访问数据区。

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 列表,验证注册是否成功。