2. Metadata数据结构:CameraMetadata类、Key-Value存储模型、基本数据类型与数组类型

在Camera HAL框架中,Metadata是连接应用层、框架层与硬件层的核心数据载体。理解其数据结构是掌握Metadata生成与消费机制的基础。本章将深入剖析CameraMetadata类的设计、Key-Value存储模型以及支持的基本数据类型与数组类型。

2.1 CameraMetadata类设计

CameraMetadata是Android框架层对Metadata数据的封装类,位于android.hardware.camera2包中。它本质上是一个类型安全的键值对容器,内部通过一个long类型的Native指针持有C++层的CameraMetadata对象。

核心设计要点:
  • 不可变性(Immutability):一旦构建完成,CameraMetadata实例不可修改,保证跨进程传递时的线程安全。
  • 类型安全:每个Key都关联特定的数据类型,编译期即可检查类型匹配。
  • 高效序列化:内部使用紧凑的二进制格式,支持Binder高效传输。

CameraMetadata类的主要方法包括:

方法 说明 返回值类型
getKeys() 获取所有包含的Key集合 List<Key<?>>
get(Key<T> key) 根据Key获取对应值 T
containsKey(Key<?> key) 判断是否包含指定Key boolean
size() 返回包含的条目数量 int

2.2 Key-Value存储模型

CameraMetadata采用Key-Value存储模型,其中Key是类型安全的枚举常量,Value是对应的数据值。这种模型的设计优势在于:

  • 可扩展性:新增Metadata条目只需定义新的Key,无需修改现有数据结构。
  • 可读性:Key的命名遵循语义化规范,如Sensor.SENSITIVITY表示传感器感光度。
  • 版本兼容:框架层可以忽略不认识的Key,实现向前兼容。
Key的命名规范: 所有Key都定义在CameraCharacteristics(静态特性)和CaptureRequest/CaptureResult(动态参数)的静态内部类中,采用大类.小类的层级命名方式,例如Lens.FOCAL_LENGTH、Control.AE_MODE。

下面通过SVG图展示CameraMetadata的Key-Value存储模型结构:

CameraMetadata Key-Value存储模型 CameraMetadata Key-Value 存储模型 CameraMetadata 容器 Key: Sensor.SENSITIVITY Value: 100 (int32) Key: Lens.FOCAL_LENGTH Value: 4.32 (float) Key: Control.AE_MODE Value: CONTROL_AE_MODE_ON (byte) Key: JPEG.GPS_COORDINATES Value: [121.5, 25.0, 0.0] (double[3]) Key: STATISTICS.FACE_RECT Value: [Rect(100,200,300,400)] (Rect[]) 每个Key唯一对应一个Value Value类型由Key的泛型参数决定

2.3 基本数据类型

CameraMetadata支持多种基本数据类型,每种类型都对应一个Key<T>的泛型参数。下表列出了所有支持的基本数据类型:

Java类型 C++类型 Tag类型 字节大小 示例Key
byte uint8_t TYPE_BYTE 1 Control.AE_MODE
int int32_t TYPE_INT32 4 Sensor.SENSITIVITY
long int64_t TYPE_INT64 8 Sensor.FRAME_DURATION
float float TYPE_FLOAT 4 Lens.FOCAL_LENGTH
double double TYPE_DOUBLE 8 JPEG.GPS_COORDINATES
Rational rational_t TYPE_RATIONAL 8 Sensor.EXPOSURE_TIME
注意: Rational类型由分子(int32)和分母(int32)组成,用于表示分数值,如曝光时间。在Java层通过android.util.Rational类表示。

2.4 数组类型

除了基本类型,CameraMetadata还支持数组类型,用于表示一组相同类型的数据。数组类型在Key的泛型参数中通过[]表示:

Java类型 C++类型 Tag类型 示例Key 说明
byte[] uint8_t* TYPE_BYTE Statistics.FACE_IDS 人脸ID列表
int[] int32_t* TYPE_INT32 Sensor.ACTIVE_ARRAY_SIZE [width, height]
long[] int64_t* TYPE_INT64 Sensor.ROLLING_SHUTTER_SKEW 滚动快门偏移
float[] float* TYPE_FLOAT Lens.DISTORTION 镜头畸变系数
double[] double* TYPE_DOUBLE JPEG.GPS_COORDINATES [经度, 纬度, 海拔]
Rational[] rational_t* TYPE_RATIONAL Sensor.COLOR_TRANSFORM 颜色变换矩阵

数组类型在HAL层通过camera_metadata_entry_t结构体表示,其中count字段表示数组长度:

// HAL层Metadata条目结构体
typedef struct camera_metadata_entry {
    size_t   index;      // 条目在数组中的索引
    uint32_t type;       // 数据类型(TYPE_BYTE, TYPE_INT32等)
    uint32_t count;      // 数组元素个数(标量时为1)
    union {
        uint8_t  *u8;    // byte数组指针
        int32_t  *i32;   // int32数组指针
        int64_t  *i64;   // int64数组指针
        float    *f;     // float数组指针
        double   *d;     // double数组指针
        camera_metadata_rational_t *r; // Rational数组指针
    } data;
} camera_metadata_entry_t;

2.5 数据类型与数组的SVG结构图

下面的SVG图展示了CameraMetadata中基本数据类型与数组类型的内存布局差异:

基本数据类型与数组类型内存布局 基本数据类型 vs 数组类型 内存布局 标量类型(Scalar) Key: Sensor.SENSITIVITY Value: 100 (int32, count=1) Key: Lens.FOCAL_LENGTH Value: 4.32 (float, count=1) count = 1,表示单个值 data指针指向单个元素 内存占用 = 类型大小 × 1 数组类型(Array) Key: Sensor.ACTIVE_ARRAY_SIZE Value: [1920, 1080] (int32[2], count=2) Key: Lens.DISTORTION Value: [0.01, -0.02, 0.005] (float[3], count=3) count > 1,表示多个值 data指针指向连续内存块 内存占用 = 类型大小 × count

2.6 代码示例:读取Metadata数据

以下代码展示了如何在应用层通过CameraMetadata类读取不同类型的数据:

// 从CaptureResult中读取Metadata
CaptureResult result = captureSession.capture(...);

// 读取标量类型
Integer sensitivity = result.get(CaptureResult.SENSOR_SENSITIVITY);
Float focalLength = result.get(CaptureResult.LENS_FOCAL_LENGTH);
Byte aeMode = result.get(CaptureResult.CONTROL_AE_MODE);

// 读取数组类型
int[] activeArraySize = result.get(CaptureResult.SENSOR_ACTIVE_ARRAY_SIZE);
float[] distortion = result.get(CaptureResult.LENS_DISTORTION);
double[] gpsCoords = result.get(CaptureResult.JPEG_GPS_COORDINATES);

// 读取Rational类型
Rational exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);

// 遍历所有Key
for (CaptureResult.Key<?> key : result.getKeys()) {
    Object value = result.get(key);
    Log.d("Metadata", "Key: " + key.getName() + ", Value: " + value);
}
最佳实践: 在读取Metadata时,始终使用containsKey()方法检查Key是否存在,避免因设备不支持该特性而返回null导致的空指针异常。

2.7 数据类型选择原则

在HAL层生成Metadata时,选择合适的数据类型需要遵循以下原则:

  • 精度需求:整数类型优先使用int32,需要更大范围时使用int64。
  • 小数精度:一般精度使用float,高精度(如GPS坐标)使用double。
  • 枚举值:使用byte类型表示枚举,节省空间。
  • 分数值:使用Rational类型避免浮点误差,如曝光时间。
  • 多值数据:使用数组类型,如颜色变换矩阵、畸变系数等。

通过本章的学习,你应该已经掌握了CameraMetadata的数据结构设计、Key-Value存储模型以及基本数据类型与数组类型的区别。这些知识将为后续理解Metadata的生成流程与消费机制奠定坚实的基础。