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,实现向前兼容。
CameraCharacteristics(静态特性)和CaptureRequest/CaptureResult(动态参数)的静态内部类中,采用大类.小类的层级命名方式,例如Lens.FOCAL_LENGTH、Control.AE_MODE。
下面通过SVG图展示CameraMetadata的Key-Value存储模型结构:
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中基本数据类型与数组类型的内存布局差异:
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);
}
containsKey()方法检查Key是否存在,避免因设备不支持该特性而返回null导致的空指针异常。
2.7 数据类型选择原则
在HAL层生成Metadata时,选择合适的数据类型需要遵循以下原则:
- 精度需求:整数类型优先使用
int32,需要更大范围时使用int64。 - 小数精度:一般精度使用
float,高精度(如GPS坐标)使用double。 - 枚举值:使用
byte类型表示枚举,节省空间。 - 分数值:使用
Rational类型避免浮点误差,如曝光时间。 - 多值数据:使用数组类型,如颜色变换矩阵、畸变系数等。
通过本章的学习,你应该已经掌握了CameraMetadata的数据结构设计、Key-Value存储模型以及基本数据类型与数组类型的区别。这些知识将为后续理解Metadata的生成流程与消费机制奠定坚实的基础。