Android Camera Metadata

什么是metadata?

之前一直没有注意到metadata的标准定义,在Android文档中有如下的描述:

要支持通过 Android 框架保存原始图片文件,需要具有大量有关传感器特性的元数据,包括色彩空间和镜头遮蔽功能等信息。

其中大多数信息是相机子系统的静态属性,因此可以在配置任何输出管道或提交任何请求之前进行查询。新的相机 API 极大地扩展了 getCameraInfo() 方法提供的信息,以便将此类信息提供给应用。

此外,手动控制相机子系统需要各种设备提供的有关其当前状态的反馈,以及在捕获指定帧时使用的实际参数。必须在输出元数据中包含硬件实际使用的控制(曝光时间、帧时长和感光度)的实际值。这一点至关重要,这样应用就知道限制或舍入何时发生,并且可以补偿用于图片捕获的实际设置。

例如,如果应用在请求中将帧时长设置为 0,则 HAL 必须将帧时长限制到该请求的实际最小帧时长,并在输出结果元数据中报告这一钳位最小持续时间。

因此,如果应用需要实现一个自定义 3A 例程(例如,为了适当地测量 HDR 连拍),则需要知道用于捕获其收到的最新一组结果的设置,以便更新下一个请求的设置。因此,新的相机 API 会向每个捕获的帧添加大量动态元数据。这包括用于捕获的已请求参数和实际参数,以及时间戳和统计信息生成器输出等其他每帧元数据。

从以上描述可以推测出metadata可能是一些传感器的静态数据,也可能是一些控制相机的参数以及相机实际运行时设置的参数。

metadata的存储结构

metadata最原始的定义应该在system\media\camera目录下。metadata有如下数据结构:

  1. struct camera_metadata {
  2.     metadata_size_t          size;
  3.     uint32_t                 version;
  4.     uint32_t                 flags;
  5.     metadata_size_t          entry_count;
  6.     metadata_size_t          entry_capacity;
  7.     metadata_uptrdiff_t      entries_start; // Offset from camera_metadata
  8.     metadata_size_t          data_count;
  9.     metadata_size_t          data_capacity;
  10.     metadata_uptrdiff_t      data_start; // Offset from camera_metadata
  11.     uint32_t                 padding;    // padding to 8 bytes boundary
  12.     metadata_vendor_id_t     vendor_id;
  13. };

我感觉这个结构体的起名有点误导性,尤其在我还完全不知道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字段,额外数据区域的偏移值。

接着需要了解表项的定义:

  1. typedef struct camera_metadata_buffer_entry {
  2.     uint32_t tag;
  3.     uint32_t count;
  4.     union {
  5.         uint32_t offset;
  6.         uint8_t  value[4];
  7.     } data;
  8.     uint8_t  type;
  9.     uint8_t  reserved[3];
  10. } camera_metadata_buffer_entry_t;

表项中表明type类型的数据有count个,如果数据不大于4个字节则直接存在表项中,否则用offset字段表示存储数据相对于头部的偏移值。

表项中的tag字段

从定义中了解到metadata有各种不同的含义,那么是如何确定代表的具体是哪一个参数呢?用的就是表项中的tag字段。一开始我在代码中看到类似section的字眼,并在网上看到一些分布图,让我以为metadata的各个参数是固定分配在内存中的。

tag字段就是一个整数,每一个数字一一映射成不同的参数。camera_metadata_tag结构体里枚举了各个数字对应的含义。

Android中对数字进行了进一步管理,每1<<16个数分为一个section。可以在如下代码中看到,Android定义了多个节,并从0x8000节开始留给厂商:

  1. typedef enum camera_metadata_section {
  2.     ANDROID_COLOR_CORRECTION,
  3.     ANDROID_CONTROL,
  4.     ANDROID_DEMOSAIC,
  5.     ANDROID_EDGE,
  6.     ANDROID_FLASH,
  7.     ANDROID_FLASH_INFO,
  8.     ANDROID_HOT_PIXEL,
  9.     ANDROID_JPEG,
  10.     ANDROID_LENS,
  11.     ANDROID_LENS_INFO,
  12.     ANDROID_NOISE_REDUCTION,
  13.     ANDROID_QUIRKS,
  14.     ANDROID_REQUEST,
  15.     ANDROID_SCALER,
  16.     ANDROID_SENSOR,
  17.     ANDROID_SENSOR_INFO,
  18.     ANDROID_SHADING,
  19.     ANDROID_STATISTICS,
  20.     ANDROID_STATISTICS_INFO,
  21.     ANDROID_TONEMAP,
  22.     ANDROID_LED,
  23.     ANDROID_INFO,
  24.     ANDROID_BLACK_LEVEL,
  25.     ANDROID_SYNC,
  26.     ANDROID_REPROCESS,
  27.     ANDROID_DEPTH,
  28.     ANDROID_LOGICAL_MULTI_CAMERA,
  29.     ANDROID_DISTORTION_CORRECTION,
  30.     ANDROID_SECTION_COUNT,
  31.  
  32.     VENDOR_SECTION = 0x8000
  33. } camera_metadata_section_t;

总结和思考

在了解了camera_metadata的结构之后,相关的函数就是在这个结构上进行增删改查等操作,就不再赘述。

同时还有以下疑惑,需要继续阅读代码:

1. 相机是怎么根据metadata进行不同操作的。

2. 厂商的metadata是否也是基于上述Android的数据结构进行管理的。