Android Camera Metadata
什么是metadata?
之前一直没有注意到metadata的标准定义,在Android文档中有如下的描述:
要支持通过 Android 框架保存原始图片文件,需要具有大量有关传感器特性的元数据,包括色彩空间和镜头遮蔽功能等信息。
其中大多数信息是相机子系统的静态属性,因此可以在配置任何输出管道或提交任何请求之前进行查询。新的相机 API 极大地扩展了 getCameraInfo() 方法提供的信息,以便将此类信息提供给应用。
此外,手动控制相机子系统需要各种设备提供的有关其当前状态的反馈,以及在捕获指定帧时使用的实际参数。必须在输出元数据中包含硬件实际使用的控制(曝光时间、帧时长和感光度)的实际值。这一点至关重要,这样应用就知道限制或舍入何时发生,并且可以补偿用于图片捕获的实际设置。
例如,如果应用在请求中将帧时长设置为 0,则 HAL 必须将帧时长限制到该请求的实际最小帧时长,并在输出结果元数据中报告这一钳位最小持续时间。
因此,如果应用需要实现一个自定义 3A 例程(例如,为了适当地测量 HDR 连拍),则需要知道用于捕获其收到的最新一组结果的设置,以便更新下一个请求的设置。因此,新的相机 API 会向每个捕获的帧添加大量动态元数据。这包括用于捕获的已请求参数和实际参数,以及时间戳和统计信息生成器输出等其他每帧元数据。
从以上描述可以推测出metadata可能是一些传感器的静态数据,也可能是一些控制相机的参数以及相机实际运行时设置的参数。
metadata的存储结构
metadata最原始的定义应该在system\media\camera目录下。metadata有如下数据结构:
- struct camera_metadata {
- metadata_size_t size;
- uint32_t version;
- uint32_t flags;
- metadata_size_t entry_count;
- metadata_size_t entry_capacity;
- metadata_uptrdiff_t entries_start; // Offset from camera_metadata
- metadata_size_t data_count;
- metadata_size_t data_capacity;
- metadata_uptrdiff_t data_start; // Offset from camera_metadata
- uint32_t padding; // padding to 8 bytes boundary
- metadata_vendor_id_t vendor_id;
- };
我感觉这个结构体的起名有点误导性,尤其在我还完全不知道metadata是什么意思的时候,乍一看让人以为这个结构所存的内容就是metadata。我感觉起名为camera_metadata_header更为合适。
在代码的注释里有一张metadata的存储结构图,metadata存储结构分为三部分:头部、表项、额外数据。在内存上的分布全部都是连续的,图中的"reserved for future expansion"没有预留,只有因为对齐而产生的未用位置。

再对着以上结构图,解释camera_metadata各个成员的含义,就能了解头部如何定位表项区域和额外数据区域,以及如何管理数据的:
●size字段是整个metadata所占的大小,单位是字节。
●flags字段,目前知道的flag是标记表项是否有序。
●entry_count字段,当前表项的个数,单位是个。
●entry_capacity字段,可容纳的表项个数,单位是个。
●entries_start字段,表项区域的偏移值。
●data_count字段,当前所存数据的字节数。
●data_capacity字段,可容纳数据的字节数。
●data_start字段,额外数据区域的偏移值。
接着需要了解表项的定义:
- typedef struct camera_metadata_buffer_entry {
- uint32_t tag;
- uint32_t count;
- union {
- uint32_t offset;
- uint8_t value[4];
- } data;
- uint8_t type;
- uint8_t reserved[3];
- } camera_metadata_buffer_entry_t;
表项中表明type类型的数据有count个,如果数据不大于4个字节则直接存在表项中,否则用offset字段表示存储数据相对于头部的偏移值。
表项中的tag字段
从定义中了解到metadata有各种不同的含义,那么是如何确定代表的具体是哪一个参数呢?用的就是表项中的tag字段。一开始我在代码中看到类似section的字眼,并在网上看到一些分布图,让我以为metadata的各个参数是固定分配在内存中的。
tag字段就是一个整数,每一个数字一一映射成不同的参数。camera_metadata_tag结构体里枚举了各个数字对应的含义。
Android中对数字进行了进一步管理,每1<<16个数分为一个section。可以在如下代码中看到,Android定义了多个节,并从0x8000节开始留给厂商:
- typedef enum camera_metadata_section {
- ANDROID_COLOR_CORRECTION,
- ANDROID_CONTROL,
- ANDROID_DEMOSAIC,
- ANDROID_EDGE,
- ANDROID_FLASH,
- ANDROID_FLASH_INFO,
- ANDROID_HOT_PIXEL,
- ANDROID_JPEG,
- ANDROID_LENS,
- ANDROID_LENS_INFO,
- ANDROID_NOISE_REDUCTION,
- ANDROID_QUIRKS,
- ANDROID_REQUEST,
- ANDROID_SCALER,
- ANDROID_SENSOR,
- ANDROID_SENSOR_INFO,
- ANDROID_SHADING,
- ANDROID_STATISTICS,
- ANDROID_STATISTICS_INFO,
- ANDROID_TONEMAP,
- ANDROID_LED,
- ANDROID_INFO,
- ANDROID_BLACK_LEVEL,
- ANDROID_SYNC,
- ANDROID_REPROCESS,
- ANDROID_DEPTH,
- ANDROID_LOGICAL_MULTI_CAMERA,
- ANDROID_DISTORTION_CORRECTION,
- ANDROID_SECTION_COUNT,
- VENDOR_SECTION = 0x8000
- } camera_metadata_section_t;
总结和思考
在了解了camera_metadata的结构之后,相关的函数就是在这个结构上进行增删改查等操作,就不再赘述。
同时还有以下疑惑,需要继续阅读代码:
1. 相机是怎么根据metadata进行不同操作的。
2. 厂商的metadata是否也是基于上述Android的数据结构进行管理的。