Android 中的 Metadata 框架与 Tag 系统详解:图像控制与参数管理的关键基石

关键词 :CameraMetadata、CaptureRequest、CaptureResult、Key、Tag、参数控制、图像回调、HAL、元数据映射


摘要

在 Android Camera2 架构中,Metadata 框架承担了 App 层与 HAL 之间 图像参数传递、状态同步与能力描述 的核心角色。无论是对焦区域、曝光策略,还是图像方向、白平衡、闪光灯状态,都依赖于 CameraMetadata 中的 KeyTag 系统进行精准配置与读取。
本文围绕 CaptureRequestCaptureResult 的 Metadata 使用逻辑,深入剖析 Tag 结构定义、数据流转路径、HAL 交互细节以及实战开发中如何高效调试与扩展。通过对当前 Android 13/14 中 Metadata 框架的解构,帮助开发者掌握图像参数控制的底层原理,并在多平台环境中实现可复用、可调优的相机系统设计。


目录


一、Metadata 在 Camera 系统中的核心角色与分类

  • CameraMetadata 的设计初衷与架构边界
  • 三种 Metadata 类型及其职责:Static、Request、Result
  • CaptureRequest 与 CaptureResult 的流转路径
  • Metadata 在 Reprocess、ZSL、HDR 模式下的作用拓展

二、CameraMetadata.Key:Tag 的唯一标识与数据结构定义

  • Key 的语法定义与模板结构(类型泛化)
  • 系统预定义 Key 与平台自定义 Key 的命名约定
  • Key → Tag 编译过程与 metadata_vendor_tag.xml 使用方式
  • 常见 Key 示例解析(如 CONTROL_AF_MODE、SENSOR_EXPOSURE_TIME)

三、静态 Metadata(Static Characteristics)的能力宣告逻辑

  • 如何读取设备支持能力(使用 CameraCharacteristics
  • 常用字段含义解读(如 REQUEST_AVAILABLE_CAPABILITIES、SCALER_STREAM_CONFIGURATION_MAP)
  • 各平台扩展能力读取方法(QTI、MTK 自定义扩展域)
  • 实战中使用静态 Metadata 进行相机初始化与能力判断

四、请求 Metadata:CaptureRequest 的参数配置策略

  • 如何构造 CaptureRequest 设置曝光、焦距、白平衡等参数
  • 自动控制 vs 手动控制模式切换策略(CONTROL_MODE_OFF)
  • 多参数批量设置技巧与状态机调试建议
  • 实战场景:实现手动对焦 + 曝光锁定的参数组合配置

五、结果 Metadata:CaptureResult 的状态回传与解析技巧

  • 回调路径:从 HAL 到 CameraDevice.StateCallback
  • 如何通过 onCaptureCompleted() 获取关键图像参数
  • 实时读取对焦状态、快门延迟、帧时间戳等
  • 结合 TotalCaptureResultPartialResult 的性能优化思路

六、Metadata 与 HAL 的数据流结构与跨版本兼容机制

  • HAL 如何实现 Metadata 的结构打包与通信
  • Type 对应表:int、byte、float、rational 的传输格式
  • Tag ID 与 Key 的双向映射关系
  • AIDL/HIDL 模型下的 Metadata 数据适配策略

七、实战调试与参数验证建议

  • 使用 adb shell dumpsys media.camera 检查 Metadata 设置与结果
  • 如何借助 logcat 打印自定义 Key 的设置值与结果值
  • 自定义扩展 Metadata 调试路径(如人像虚化强度、人脸检测区域)
  • ImageReader 中关联 Metadata 进行拍照日志打通

八、多平台开发中的 Metadata 策略抽象与接口封装

  • 不同平台对 Key 支持范围的差异化(如 MTK 特有 KEY_MTK_ 前缀)
  • 构建统一参数配置模型的建议(如 MetadataAdapter 工厂封装)
  • 如何为多个平台动态生成 CaptureRequest 参数集
  • 大型项目中 Metadata 与 UseCase 解耦的实践范式

一、Metadata 在 Camera 系统中的核心角色与分类

在 Android Camera2 架构中, CameraMetadata 是连接 应用层 → 框架层 → HAL → Sensor/ISP 的关键参数控制与状态传输媒介。所有的相机行为 —— 包括启动预览、聚焦模式切换、手动曝光控制、闪光灯触发、图像后处理设置,乃至最终图像帧的状态反馈 —— 都由 Metadata 系统在多个阶段以结构化形式描述与传递。

本章将围绕 CameraMetadata 的设计初衷、类型划分、流转通路与其在高级场景(如 Reprocessing、ZSL、HDR)下的能力体现进行全面解析,构建清晰的底层数据认知图谱。


1. CameraMetadata 的设计初衷与架构边界

在 Camera2 接口从原有的拍照预览黑盒(Camera API)转向完整可控的状态机模型后,Google 推出了 CameraMetadata 类来承载图像控制的细粒度需求。其设计目标包括:

  • 统一参数格式 :用于横跨 Java/C++ 层的参数传输;
  • 类型安全定义 :所有参数(Key)都拥有明确的类型与作用域;
  • 多阶段隔离 :可区分静态能力、请求控制与结果反馈;
  • 平台可扩展 :支持厂商自定义 Tag,提升 ISP 能力接入弹性。

其核心基类为 android.hardware.camera2.CameraMetadata<Key> ,并派生出以下三种关键子类,分别对应不同的数据阶段。


2. 三种 Metadata 类型及其职责:Static、Request、Result

类型Java 对应类职责说明
Static MetadataCameraCharacteristics描述摄像头在运行前的静态能力,如支持的分辨率、对焦模式、Sensor 特性等。初始化时获取,不随帧变化。
Request MetadataCaptureRequest表示一帧图像采集前的控制参数配置,如曝光时间、ISO、对焦模式、AE/AF 触发等。由 App 主动设置,发给 HAL 执行。
Result MetadataCaptureResultTotalCaptureResult表示每帧图像完成后的状态反馈,如实际曝光时间、焦距、对焦成功与否、帧 ID 等。由 HAL 回传。

这三者构成了 Android 相机完整的“ 参数 → 控制 → 状态反馈 ”三阶段信息链。


3. CaptureRequest 与 CaptureResult 的流转路径

以一次典型拍照为例,Metadata 数据在系统中经历如下流转过程:

  1. App 构建请求

    • 使用 CameraDevice.createCaptureRequest() 创建 CaptureRequest.Builder
    • 通过 set() 方法设置参数,如 CONTROL_AF_MODESENSOR_EXPOSURE_TIME
    • 构建出完整的 CaptureRequest
  2. 系统发送请求

    • 请求发送至 CameraService ,进入 HAL 调用链;
    • HAL 接收后调用 ISP 控制器,配置 Sensor、镜头、曝光电路等硬件模块;
    • 同时建立缓冲队列准备帧输出。
  3. 图像帧生成 → 状态上报

    • 当一帧图像被捕获后,HAL 通过 Metadata 描述采集结果;
    • 系统回调 CameraCaptureSession.CaptureCallbackonCaptureCompleted() ,带回 CaptureResult
    • 应用层可读取如 SENSOR_TIMESTAMPLENS_FOCUS_DISTANCE 等参数,进一步处理或调试。
  4. 高级功能链路支持

    • 若开启 ZSL、HDR 或多帧 Reprocess,Metadata 将用于描述缓存帧状态、合成参数、目标图像效果目标等;
    • ReprocessCaptureRequest 中绑定前一帧的 TotalCaptureResult ,实现 ISP 重处理复用。

4. Metadata 在 Reprocess、ZSL、HDR 模式下的作用拓展

Metadata 并不仅是“参数传输”,在实际工程中还承担着核心的 帧标识与语义绑定 职责:

✅ Reprocess 模式:
  • 绑定 TotalCaptureResultReprocessCaptureRequest
  • 传入帧的所有状态信息必须一致,包括 AE/AF 状态、Sensor 参数、Scene 模式;
  • 通过 Metadata 提供完整的帧环境描述,供 ISP 做离线优化。
✅ ZSL(Zero Shutter Lag)模式:
  • 系统缓存多个帧及其 CaptureResult
  • 拍照时选择最佳帧(如对焦成功 + 曝光合适);
  • 再将该帧作为输入执行 Reprocess。
✅ HDR 模式:
  • Metadata 控制不同帧的 EXPOSURE_TIMESENSOR_SENSITIVITY
  • 设置 CONTROL_AE_MODE = AE_MODE_OFF 并传入多帧手动参数;
  • 每帧的 CaptureResult 将反映真实拍摄状态,供后处理融合算法使用。

通过对 Metadata 分类、结构与流转路径的理解,开发者可掌握 Camera2 架构的控制逻辑核心,为后续高阶图像参数配置、平台适配与性能调优奠定基础。

二、CameraMetadata.Key:Tag 的唯一标识与数据结构定义

在 Android Camera2 架构中, CameraMetadata.Key<T> 是实现参数设置与状态传输的核心抽象。它不仅用于标识每一项元数据的含义(例如自动对焦模式、曝光时间等),同时也定义了这些数据的类型、生命周期与流向。系统层、平台厂商甚至 App 开发者,都依赖 Key 来精准读取与配置相机参数。

本章将深入解析 Key 的数据结构、生成方式与实际工程中的使用场景,帮助开发者从源码层理解 Camera Metadata 系统的构建原理。


1. Key 的语法定义与模板结构(类型泛化)

CameraMetadata 的每一个参数都通过 Key<T> 泛型类来定义,其内部结构如下:

public final class CameraMetadata.Key<T> {
    private final String name;         // 字符串形式的唯一标识
    private final Class<T> type;       // 数据类型(如 Integer.class)
}

Java 层的 CameraMetadata 派生类(如 CaptureRequestCameraCharacteristics )会暴露大量预定义的静态 Key。例如:

public static final Key<Integer> CONTROL_AF_MODE;
public static final Key<Long> SENSOR_EXPOSURE_TIME;
public static final Key<Range<Integer>> CONTROL_AE_TARGET_FPS_RANGE;

这些 Key 与底层 HAL 层的 Tag ID 一一映射。通过 Key.getName() 可以获取 Key 的全路径标识,如 "android.control.afMode"


2. 系统预定义 Key 与平台自定义 Key 的命名约定

系统预定义 Key(android.* 命名空间):

Android 官方 Camera2 API 提供了大量预定义 Key,统一以 "android." 开头,遵循模块/参数的层次化命名。例如:

  • "android.control.afMode" :自动对焦模式;
  • "android.sensor.exposureTime" :曝光时间;
  • "android.statistics.faceDetectMode" :人脸检测功能开关;
  • "android.jpeg.orientation" :JPEG 编码方向参数。

这些 Key 会在 AOSP 的 system/media/camera/src/camera_metadata_tags.c 中定义为枚举值(Tag ID),供 HAL 解析并使用。

平台自定义 Key(vendor.* 命名空间):

SoC 厂商可根据自身 ISP 能力扩展 Tag 系统,统一放在 "vendor.*" 命名空间。例如:

  • "com.qti.chi.exposure.tableIndex" :高通平台曝光曲线索引;
  • "com.mediatek.control.capture.shutterDelay" :MTK 平台快门延迟开关;
  • "com.samsung.sensor.dual_iso_mode" :三星平台双 ISO 模式开关。

自定义 Key 一般需通过 metadata_vendor_tag.xml 声明注册,并由 HAL 实现解析。


3. Key → Tag 编译过程与 metadata_vendor_tag.xml 使用方式

自定义 Metadata Key 要实现系统识别,需完成如下注册流程:

步骤 1:定义 metadata_vendor_tag.xml
<vendorTags>
  <tag id="600001" name="com.qti.chi.exposure.tableIndex">
    <type>int32</type>
    <visibility>public</visibility>
    <section>com.qti.chi.exposure</section>
  </tag>
</vendorTags>

步骤 2:使用 camera_metadata_tag_info 工具编译

在编译 AOSP 或 BSP 时,系统会将该 XML 编译成 C 语言常量,用于 HAL 注册与识别。

生成路径通常位于:

out/target/product/<device>/gen/ETC/camera_metadata_vendor_tags.h

其中定义了:

#define VENDOR_TAG_COM_QTI_CHI_EXPOSURE_TABLEINDEX 600001

步骤 3:HAL 中注册 VendorTag 操作表
int get_tag_count();
void get_all_tags(uint32_t *tag_array);
const char* get_section_name(uint32_t tag);
const char* get_tag_name(uint32_t tag);
int get_tag_type(uint32_t tag);

步骤 4:Java 层通过 CameraCharacteristics.get() / CaptureResult.get() 获取值

开发者便可通过如下方式读取或设置:

CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(...);
builder.set(VENDOR_CHI_EXPOSURE_TABLE_INDEX, 3);


4. 常见 Key 示例解析(如 CONTROL_AF_MODE、SENSOR_EXPOSURE_TIME)

CONTROL_AF_MODE
Key<Integer> CONTROL_AF_MODE = new Key<>("android.control.afMode", Integer.class);

  • 值域: OFF(0) , AUTO(1) , MACRO(2) , CONTINUOUS_VIDEO(3) , CONTINUOUS_PICTURE(4)
  • 使用场景:控制对焦方式,建议拍照时设为 CONTINUOUS_PICTURE
SENSOR_EXPOSURE_TIME
Key<Long> SENSOR_EXPOSURE_TIME = new Key<>("android.sensor.exposureTime", Long.class);

  • 单位:纳秒(ns)
  • 使用场景:手动控制曝光时设置,配合 CONTROL_AE_MODE = OFF
  • 合理范围: 1e4 ~ 3e8 (需查询静态 Metadata 中支持范围)
JPEG_ORIENTATION
Key<Integer> JPEG_ORIENTATION = new Key<>("android.jpeg.orientation", Integer.class);

  • 控制输出图像的旋转角度,常用值为:0、90、180、270
  • 通常根据 Display.getRotation() 决定
  • 设置不影响原始图像流,仅对 JPEG 编码图像生效

通过掌握 Key 的语法结构与注册机制,开发者不仅可以灵活控制系统已有参数,还能在自研 ISP 算法、平台适配过程中扩展能力,构建具有高自由度与可控性的图像采集控制体系。

四、请求 Metadata:CaptureRequest 的参数配置策略

在 Android Camera2 架构中, CaptureRequest 是发送给 HAL 的“拍摄请求载体”,其中封装了控制相机行为的全部参数,例如曝光、对焦、白平衡、ISO、图像增强等。它代表一次具体图像采集行为之前的控制设置,构建良好的 CaptureRequest 是确保拍照/预览/视频稳定运行的关键。

本章将结合系统结构与实际开发经验,深入讲解 CaptureRequest 的构造逻辑、自动与手动控制模式的切换方式、参数调试与调优策略,并通过一个完整实战案例展示如何实现“手动对焦 + 曝光锁定”的组合控制。


1. 如何构造 CaptureRequest 设置曝光、焦距、白平衡等参数

构造 CaptureRequest 的标准流程如下:

CameraCaptureSession session;
CameraDevice cameraDevice;

CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

// 设置参数
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON);
builder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);

// 绑定输出 Surface
builder.addTarget(previewSurface);

// 构建 CaptureRequest
CaptureRequest request = builder.build();

// 提交请求
session.setRepeatingRequest(request, captureCallback, handler);

常见参数设置列表:

参数 Key说明
CONTROL_AF_MODE自动对焦模式(如 AUTO , CONTINUOUS_PICTURE
CONTROL_AE_MODE自动曝光模式( ON , OFF
SENSOR_EXPOSURE_TIME曝光时间(单位 ns,仅手动模式有效)
LENS_FOCUS_DISTANCE焦距控制(单位 diopters,0 表示无限远)
CONTROL_AWB_MODE自动白平衡模式
NOISE_REDUCTION_MODE图像降噪参数
EDGE_MODE锐化处理设置

2. 自动控制 vs 手动控制模式切换策略( CONTROL_MODE_OFF

Camera2 中控制模式的切换围绕 CONTROL_MODE 和相关子模块展开:

自动模式(默认):
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO);

表示由系统 ISP 全权接管 AE/AF/AWB 控制。

手动控制模式:
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 20000000L); // 20ms
builder.set(CaptureRequest.SENSOR_SENSITIVITY, 800);         // ISO800
builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 0.5f);       // 手动焦距

⚠️ 注意:进入手动模式需同时关闭 AEAF ,否则 HAL 会报错或忽略设置。

切换过程建议等待 2-3 帧后稳定生效,可通过监听 CaptureResult 中的状态字段确认。


3. 多参数批量设置技巧与状态机调试建议

✅ 批量设置策略:
  • 尽可能在同一个 CaptureRequest.Builder 中完成所有相关参数配置;
  • 避免频繁重建 Builder:使用 session.setRepeatingRequest() 结合修改参数进行动态更新;
  • 对于一次性参数(如 CONTROL_AF_TRIGGER ),使用 session.capture() 提交单帧请求。
// AF 触发一次
builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START);
session.capture(builder.build(), callback, handler);

✅ 状态调试建议:
  • 使用 CaptureCallback.onCaptureCompleted() 获取 TotalCaptureResult
  • 检查实际应用的曝光值、焦距、帧 ID 等是否与设置匹配;
  • 打印如下参数用于对比:
Long exp = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
Float focus = result.get(CaptureResult.LENS_FOCUS_DISTANCE);
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);

结合 logcatsystrace 可进一步排查帧落、参数失效等问题。


4. 实战场景:实现手动对焦 + 曝光锁定的参数组合配置

以一个自定义拍照场景为例,目标是在低光下使用手动对焦与固定曝光参数以获取更可控图像:

CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);

// 切换为完全手动模式
builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);

// 曝光参数(20ms 曝光时间 + ISO 800)
builder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_OFF);
builder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, 20000000L);
builder.set(CaptureRequest.SENSOR_SENSITIVITY, 800);

// 手动对焦(焦距设置为 0.4 米)
builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_OFF);
builder.set(CaptureRequest.LENS_FOCUS_DISTANCE, 2.5f); // 单位为 1/m,2.5 = 0.4m

// 设置白平衡为自动
builder.set(CaptureRequest.CONTROL_AWB_MODE, CaptureRequest.CONTROL_AWB_MODE_AUTO);

// 提交拍照请求
builder.addTarget(jpegSurface);
session.capture(builder.build(), captureCallback, handler);

此组合适用于拍摄静物、弱光场景下对焦/曝光可预测、图像一致性要求高的应用(如文档识别、人脸图像采集)。


合理构建 CaptureRequest 并精准控制参数,是实现 Camera2 复杂图像策略的关键能力。

五、结果 Metadata:CaptureResult 的状态回传与解析技巧

在 Android Camera2 架构中, CaptureResult 是 HAL 向应用层返回的 图像采集结果状态描述 ,代表了某一帧实际拍摄过程中硬件所执行的操作与反馈信息。开发者可以通过它获取诸如曝光时间、焦距、ISO 值、快门时间戳、对焦成功与否等详细参数,在图像分析、调试优化、拍照时序控制等场景中发挥关键作用。

本章将结合 Camera 系统回调机制与实践经验,系统性梳理 CaptureResult 的传递路径、典型用法、性能优化策略,以及如何结合 TotalCaptureResultPartialResult 实现更高效的帧级控制与反馈管理。


1. 回调路径:从 HAL 到 CameraDevice.StateCallback

CaptureResult 是随拍照/预览帧完成后通过回调异步返回的,其整体回调链如下:

HAL → CameraService → CameraDeviceClient → CameraCaptureSessionImpl → App Callback

具体代码表现为:

CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() {
    @Override
    public void onCaptureCompleted(@NonNull CameraCaptureSession session,
                                   @NonNull CaptureRequest request,
                                   @NonNull TotalCaptureResult result) {
        // 处理每帧结果
    }
};

系统每次提交请求( setRepeatingRequestcapture )后,收到结果帧时将调用该回调方法,并传递对应帧的 CaptureRequestCaptureResult 对象。


2. 如何通过 onCaptureCompleted() 获取关键图像参数

onCaptureCompleted() 中,开发者可使用 result.get() 方法获取状态参数:

Long exposureTime = result.get(CaptureResult.SENSOR_EXPOSURE_TIME);
Integer iso = result.get(CaptureResult.SENSOR_SENSITIVITY);
Float focusDistance = result.get(CaptureResult.LENS_FOCUS_DISTANCE);
Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);

这些参数是摄像头 实际执行后的反馈状态 ,而非应用设置值。

典型参数解析:
参数 Key类型描述
SENSOR_EXPOSURE_TIMELong实际曝光时间,单位为 ns
SENSOR_SENSITIVITYInteger实际 ISO
LENS_FOCUS_DISTANCEFloat实际焦距(1/米)
CONTROL_AF_STATEInteger对焦状态: PASSIVE_SCANINGFOCUSED_LOCKED
SENSOR_TIMESTAMPLong图像采集时的时间戳,用于同步
JPEG_ORIENTATIONInteger拍照时设置的旋转角度

3. 实时读取对焦状态、快门延迟、帧时间戳等

开发中可以结合 CaptureResult 实现对帧执行情况的状态追踪与 UI 联动,例如:

✅ 判断对焦是否成功:
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState != null && afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED) {
    // 对焦完成,可开始拍照
}

✅ 获取帧时间戳,实现图像同步或帧间距测量:
Long timestamp = result.get(CaptureResult.SENSOR_TIMESTAMP);

可用于分析帧率变化、图像延迟、与外部传感器数据同步等需求。

✅ 计算快门延迟(Shutter Lag):

通过对比发送请求时间与 SENSOR_TIMESTAMP 可估算硬件响应延迟:

long now = System.nanoTime();
long shutterTime = result.get(CaptureResult.SENSOR_TIMESTAMP);
long shutterLagMs = (now - shutterTime) / 1_000_000L;


4. 结合 TotalCaptureResultPartialResult 的性能优化思路

TotalCaptureResult

默认情况下,系统只在一帧完成后返回完整的 TotalCaptureResult ,适用于需要完整参数集的逻辑,如图像分析、HDR 合成、ML 推理等。

PartialResult

为提升回调响应速度,部分厂商平台支持“ 部分结果提前返回 ”机制。通过:

int partialCount = result.getPartialResultCount();

可得知当前结果是第几部分,结合:

CaptureRequest.get(CaptureRequest.REQUEST_PARTIAL_RESULT_COUNT)

用于追踪是否为最终帧结果。

开发者可根据实际需求:

  • 通过 PartialResult 提前读取对焦/曝光状态做 UI 提示;
  • TotalCaptureResult 到来前做策略准备(如提前切换焦距);
  • 减少帧延迟与系统 wait lock,提升 UI 交互性能。

通过对 CaptureResult 中各类 Metadata 的掌握,开发者可以精准理解与控制每一帧的执行情况,并基于状态反馈实现更加稳定、响应快、体验优的相机行为控制逻辑。

六、Metadata 与 HAL 的数据流结构与跨版本兼容机制

Android Camera 系统的核心控制链路依赖于 CameraMetadata 在 Framework 层与 HAL 层之间的精确传输。Metadata 不仅用于定义参数行为,也直接参与硬件控制与图像结果的表达。为了适配多种平台版本(HIDL / AIDL)、不同 SoC 能力扩展,以及跨版本向前兼容,Android 构建了一套完整的 Metadata 数据流结构和传输机制。

本章将聚焦 Metadata 在 HAL 层的底层数据格式、类型传输结构、Tag ID 与 Key 的映射机制,以及 AIDL/HIDL 在接口演进中的适配策略与工程实践要点。


1. HAL 如何实现 Metadata 的结构打包与通信

Camera HAL 与 Framework 间的数据传输使用 camera_metadata_t 结构体,它是一种自描述的 TLV(Tag-Length-Value)结构,定义于 system/media/camera/include/system/camera_metadata.h 中:

struct camera_metadata_t {
    uint32_t version;
    uint32_t flags;
    uint32_t entry_count;
    uint32_t entry_capacity;
    uint32_t data_count;
    uint32_t data_capacity;
    // 紧跟 Entry 和 Data 区
};

每个 Entry 表示一个 Key(Tag),包含:

  • Tag ID(uint32_t)
  • Type(uint8_t)
  • Count(uint32_t)
  • Data offset(uint32_t)

例如:

entry[0]: {
  tag: 0x1001, // CONTROL_AF_MODE
  type: TYPE_BYTE,
  count: 1,
  offset: 128
}

这些结构由 HAL 实现类通过 fill_capture_result()process_capture_request() 回传或接收,并通过 camera_metadata_*() 函数进行解析与封装。


2. Type 对应表:int、byte、float、rational 的传输格式

Metadata 支持的类型为枚举 camera_metadata_type_t ,对应如下表:

Metadata 类型枚举常量内存格式示例
BYTETYPE_BYTEuint8_t开关状态
INT32TYPE_INT32int32_t曝光时间值
FLOATTYPE_FLOATfloat焦距
INT64TYPE_INT64int64_t时间戳
DOUBLETYPE_DOUBLEdouble暂不常用
RATIONALTYPE_RATIONALstruct {int32_t num; int32_t denom;}对比度、亮度比值

在 HAL 与 Framework 间通信时,HAL 返回填充的原始结构由 JNI/C++ 层封装为 Java 可读取的 CaptureResultCameraCharacteristics 等类。


3. Tag ID 与 Key 的双向映射关系

每个 Metadata 参数都由唯一的 Tag ID 定义,在 system/media/camera/include/system/camera_metadata_tags.h 中预定义,例如:

#define ANDROID_CONTROL_AF_MODE 0x1001
#define ANDROID_SENSOR_EXPOSURE_TIME 0x2001

这些 Tag ID 与 Java 层的 CameraMetadata.Key<?> 是通过反射机制映射的。

映射路径:

Java Key ("android.control.afMode")
   ⇅
CameraMetadataTag Section + Entry
   ⇅
Tag ID(如 0x1001)

在编译期,系统使用 metadata_vendor_tag.xml 自动生成 Tag 到 ID 的索引表,供 camera_metadata_enum_string() 使用,实现调试和日志映射。

厂商可通过添加自定义的 Tag Section:

<VendorTagSection name="com.vendor.camera.custom">
    <Tag name="sceneConfidence" type="float" visibility="public"/>
</VendorTagSection>

通过注册接口暴露至 Java 层供访问。


4. AIDL/HIDL 模型下的 Metadata 数据适配策略

随着 AIDL 在 Android 13+ 中替代原有 HIDL 接口,Metadata 的传输方式也做了重大演进。

✅ HIDL 模式(Android 8–12)
  • 使用 hidl_vec<uint8_t> 传输原始 camera_metadata_t 字节;
  • HAL 中通过 convertFromHidl() / convertToHidl() 进行封装;
  • 所有字段统一用 Tag ID 解析,不含结构描述信息。
✅ AIDL 模式(Android 13+)
  • AIDL 定义了结构化的 CameraMetadata AIDL 类型;
  • 使用 Parcelable 接口明确字段类型、安全边界与扩展性;
  • 支持嵌套结构与 nullable 定义,提升稳定性与错误提示能力;
  • 引入 ICameraMetadataTagDescriptor ,提供运行时 Tag 查询能力。

示例:

parcelable CameraMetadata {
  array<MetadataEntry> entries;
}

parcelable MetadataEntry {
  int tag;
  byte type;
  int count;
  byte[] data;
}

混合平台适配:

当前主流平台(如 QTI/MTK)仍在 HIDL 与 AIDL 之间做平滑过渡,常见策略包括:

  • 使用 HIDL → AIDL Adapter 在 framework 中做桥接;
  • HAL 侧提供兼容双接口入口;
  • 高通提供自定义 AIDL 接口扩展能力(如 ICustomCameraProvider);
  • 调试工具如 lshal , aidl_interface , adb shell dumpsys media.camera 可判断平台当前运行模式。

Metadata 的跨层级传输与平台适配机制,构建了 Android Camera 系统灵活可拓展的核心控制链条。理解其结构与逻辑,有助于开发者在多平台、多版本、深度定制场景中高效调试与稳定部署。

七、实战调试与参数验证建议

Android Camera2 系统虽具备高度可配置性与精细控制能力,但随之而来的是复杂的状态流转与参数交互机制。为了保证开发过程中对 Metadata 参数设置的准确性与执行结果的可控性,掌握一套系统性的调试与验证策略是非常必要的。

本章聚焦在工程实践中,如何有效调试 Camera Metadata,包括标准系统工具使用方法、自定义 Tag 的验证技巧,以及如何将底层 Metadata 与上层图像管线日志打通,形成闭环的调试路径。


1. 使用 adb shell dumpsys media.camera 检查 Metadata 设置与结果

Android 提供的 dumpsys media.camera 是排查 CameraService 状态最直接的命令之一,能展示当前设备注册情况、正在活跃的 CameraSession,以及对应 CaptureRequest / CaptureResult 中的 Metadata 关键字段。

典型使用方法

adb shell dumpsys media.camera > camera_dump.txt

可查阅内容包括:

  • 当前活跃的摄像头 ID(如 cameraId=0, facing=BACK)
  • 当前正在使用的 HAL 版本与接口方式(HIDL / AIDL)
  • 最新提交的 CaptureRequest 参数列表(关键 Metadata)
  • 最近收到的 CaptureResult 及其 Metadata 回传内容

重点关注字段

Request ID: 42
  CONTROL_AF_MODE = 1
  CONTROL_AE_EXPOSURE_COMPENSATION = 0
  SENSOR_EXPOSURE_TIME = 33300000
Result ID: 42
  CONTROL_AF_STATE = 4 (FOCUSED_LOCKED)
  LENS_STATE = 0 (STATIONARY)

建议结合实际的 UseCase 名称 / RequestID / SessionID 进行分析,可以验证设置值是否成功生效。


2. 如何借助 logcat 打印自定义 Key 的设置值与结果值

在开发调试中,可直接在回调处打印 CaptureRequest / CaptureResult 中的关键参数,结合 logcat 实时观察。

打印设置值(Request)

Log.d("CamRequest", "AF Mode: " + request.get(CaptureRequest.CONTROL_AF_MODE));
Log.d("CamRequest", "Exposure Time: " + request.get(CaptureRequest.SENSOR_EXPOSURE_TIME));

打印结果值(Result)

Log.d("CamResult", "AF State: " + result.get(CaptureResult.CONTROL_AF_STATE));
Log.d("CamResult", "Focus Distance: " + result.get(CaptureResult.LENS_FOCUS_DISTANCE));

建议加上帧 ID 以便日志对齐

Log.d("CamResult", "Frame #" + result.getFrameNumber() + ": ISO=" + result.get(CaptureResult.SENSOR_SENSITIVITY));

为防止丢帧或异常帧调试困难,可考虑添加关键字段为空时的提示逻辑,并在 SurfaceView 预览帧变化时联动验证。


3. 自定义扩展 Metadata 调试路径(如人像虚化强度、人脸检测区域)

厂商平台往往通过自定义 Metadata 扩展功能模块(如虚化强度、滤镜类型、人脸位置区域),这类 Tag 一般定义在 metadata_vendor_tag.xml 中。

调试方法如下

(1)确认是否注册成功:
adb shell dumpsys media.camera | grep VendorTagDescriptor

如果正常加载,Vendor Tag ID 区间一般是 0x80000000 以上。

(2)访问自定义字段:
CaptureResult.Key<Float> BLUR_LEVEL =
    new CaptureResult.Key<>("com.qti.camera.blur.level", Float.class);
Float blur = result.get(BLUR_LEVEL);
Log.d("CamCustom", "Blur Level = " + blur);

或针对 MTK 平台:

CaptureResult.Key<Integer> MTK_BOKEH_LEVEL =
    new CaptureResult.Key<>("com.mediatek.camera.bokeh.level", Integer.class);

注意:部分 Tag 不一定在每帧都回传,需结合 UseCase 类型判断调用时机。


4. ImageReader 中关联 Metadata 进行拍照日志打通

在拍照或图像处理管线中, ImageReader 提供的 onImageAvailable() 回调与 CaptureCallbackonCaptureCompleted() 是两条独立线程,若想实现图像 + Metadata 的对齐输出,建议使用 TagRequest ID 做中间桥接。

示例:将 Metadata 附加到 Tag 进行跨线程传递

CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(...);
builder.setTag(System.currentTimeMillis());
session.capture(builder.build(), captureCallback, handler);

onImageAvailable() 中获取:

Image image = imageReader.acquireNextImage();
Object tag = image.getTimestamp(); // 可比对 Metadata 中 SENSOR_TIMESTAMP

然后与 CaptureResult.get(SENSOR_TIMESTAMP) 做匹配,实现图像与参数对齐记录。


通过以上工具与方法,开发者可高效掌握 Camera Metadata 的传输行为、实际应用中的设置结果、扩展参数验证路径,并在复杂系统环境中实现快速调试与参数验证。

八、多平台开发中的 Metadata 策略抽象与接口封装

在面向多厂商平台(如 Qualcomm、MTK、Samsung)相机系统开发时,Metadata 的使用很难做到“一套代码跑所有机型”。不同平台对 CameraMetadata.Key<?> 的支持能力、Tag 命名、类型结构存在差异,甚至相同字段在行为层面也可能有所出入。因此在大型 Camera 工程中,必须构建一套抽象化的参数适配机制,来提升代码的可维护性、兼容性与复用能力。

本章将从平台差异识别、参数模型设计、动态构建策略与工程实践四个维度展开 Metadata 抽象的实战方法。


1. 不同平台对 Key 支持范围的差异化(如 MTK 特有 KEY_MTK_ 前缀)

✅ Qualcomm(QTI)平台:
  • 支持标准 Camera2 Key 全集;

  • 附带大量自定义扩展字段,如:

    • org.codeaurora.qcamera3.exposure_time_range
    • org.codeaurora.qcamera3.stats.is_hdr_scene
✅ MTK(联发科)平台:
  • 强依赖 HAL 层扩展字段,命名规则多为 com.mediatek.*

  • 常见如:

    • com.mediatek.control.capture.mfb.mode
    • com.mediatek.control.ae.target.fps.range
✅ Samsung Exynos:
  • 多采用专有 HAL API + 标准 Key 混合策略;
  • 有时通过厂商自定义模块注入,不直接暴露 Metadata;
  • 针对 ZSL、夜景合成、人像光效等功能 Tag 封闭性较强。

实践建议

  • 不要假定所有平台都支持某个标准 Key;
  • 对于扩展字段,应在运行时用 CameraCharacteristics.getAvailableCaptureRequestKeys() 做前置检查;
  • 平台间行为差异需文档化,归类整理便于配置适配。

2. 构建统一参数配置模型的建议(如 MetadataAdapter 工厂封装)

为了统一处理不同平台的 CaptureRequest 构造逻辑,建议构建一个类似 MetadataAdapter 的封装模块,核心职责包括:

  • 定义一套跨平台中立的参数结构(如 CameraParamSet );
  • 映射平台差异字段(如 MTK_HDR_MODEQTI_HDR_MODE );
  • 封装应用层配置逻辑与默认值处理;
  • 动态判断平台特性并注入对应参数集。

示例结构设计

class CameraParamSet {
    boolean isHDR;
    boolean isZslEnabled;
    float focusDistance;
    // ... 统一抽象字段
}

interface MetadataAdapter {
    void applyToBuilder(CaptureRequest.Builder builder, CameraParamSet paramSet);
}

针对 MTK/QTI/Exynos 分别实现不同的 Adapter 实例,在实际调用时:

MetadataAdapter adapter = MetadataAdapterFactory.create(currentPlatform);
adapter.applyToBuilder(captureBuilder, cameraParamSet);

通过这种方式实现参数配置逻辑的完全解耦和跨平台兼容。


3. 如何为多个平台动态生成 CaptureRequest 参数集

构造 CaptureRequest 参数集的流程可以按如下模式抽象:

  • 获取当前平台标识(如 SoC 厂商、系统属性)
  • 加载对应平台配置策略表(XML/JSON 或 Java 类封装)
  • 遍历参数表进行逐项判断与注入
  • 支持回退机制与日志提示(若平台不支持某个 Key)

动态生成策略建议

if (Platform.isMTK()) {
    builder.set(new CaptureRequest.Key<>("com.mediatek.control.hdr.mode", Integer.class), 1);
} else if (Platform.isQTI()) {
    builder.set(new CaptureRequest.Key<>("org.codeaurora.qcamera3.hdr.mode", Byte.class), (byte) 1);
}

在高级项目中,可以使用映射配置表:

{
  "hdr": {
    "qti": {"key": "org.codeaurora.qcamera3.hdr.mode", "type": "byte", "value": 1},
    "mtk": {"key": "com.mediatek.control.hdr.mode", "type": "int", "value": 1}
  }
}

并使用反射 + 工厂模式动态注入,提高灵活性。


4. 大型项目中 Metadata 与 UseCase 解耦的实践范式

UseCase 层(如预览、拍照、人像、美颜)不应直接感知平台级 Metadata,而是应通过中间配置模型 + Metadata 分发器进行桥接。

推荐架构设计:
[UseCase层]
     ↓
[参数策略管理器 ParamStrategyManager]
     ↓
[平台适配器 MetadataAdapter]
     ↓
[CaptureRequest.Builder]

每个 UseCase 提交的逻辑流程应如下

  1. UseCaseConfigCameraParamSet (抽象参数)
  2. CameraParamSet 交由 MetadataAdapter 进行 Key/Value 转换
  3. 注入 CaptureRequest.Builder ,完成参数组合与提交

这样可以做到:

  • UseCase 对 Metadata 的零感知
  • 多平台字段差异的最小影响面
  • 支持自动适配、参数兜底、异常降级

UseCase 层只关注业务参数,如:

captureConfig.setHdrEnabled(true);
captureConfig.setPortraitBlurLevel(0.6f);

通过策略管理器自动转换为 MTK / QTI 对应的 Metadata 设置。


多平台 Metadata 封装与抽象是大型 Camera 应用稳定运行的基础之一。在碎片化严重、定制能力强的安卓生态中,建立一套系统性、层级清晰的参数适配机制,不仅提升开发效率,也能大幅降低适配与维护成本。

本文转自 https://jc-performance.cn//online/3453_148669399.html,如有侵权,请联系删除。