2、高通平台AF架构:高通Camera子系统概览、AF算法模块位置、AF与ISP/CPP的交互

好,咱们正式进入高通平台AF架构这一章。说实话,很多做AF的工程师干了两年,可能都没搞明白自己写的代码到底跑在哪个核上、数据是怎么流转的。我刚开始接触高通平台时也踩过这个坑——调了半天AF参数,结果发现算法根本没被调用,因为ISP pipeline根本没把统计数据送过来。

这一章,我就带你把这个架构理清楚。你不需要记住每一行寄存器配置,但必须知道AF算法模块在哪儿、它跟ISP和CPP之间是怎么“对话”的。

2.1 高通Camera子系统整体架构

先看一张总览图。高通平台的Camera子系统,说白了就是三大块:传感器端(Sensor)、ISP处理管线、应用层/算法层。AF算法夹在中间,既要从ISP拿统计数据,又要通过CPP(Camera Post-Processor)把控制指令送回去。

核心要点:AF算法不是独立运行的,它依赖ISP提供的统计数据(如对比度值、相位差数据),并通过CPP或直接驱动VCM(音圈马达)来调整镜头位置。

高通Camera子系统AF架构总览 图像传感器 RAW数据输出 ISP管线 统计信息生成 CPP后处理 VCM驱动/控制 AF算法模块 搜索策略/决策 应用层/Camera HAL VCM控制反馈 关键数据流: 1. Sensor → RAW → ISP 2. ISP → 统计信息 → AF 3. AF → 决策 → CPP/VCM

这张图我建议你多看几遍。它把AF相关的数据流和控制流都画出来了。我个人习惯把这种图贴在工位上,调试时一眼就能定位问题出在哪个环节。

2.2 AF算法模块在系统中的位置

AF算法模块到底在哪儿?这个问题我问过不少新人,答案五花八门。有人说是ISP内部的硬件模块,有人说是CPP里的一个线程。其实都不完全对。

在高通平台上,AF算法模块是一个软件模块,运行在应用处理器(AP)侧,通常位于Camera HAL层或者一个独立的AF Daemon进程中。它不跑在ISP内部,也不跑在CPP内部。

层级 位置 职责 典型文件/模块
应用层 Camera App 发起AF请求、设置AF模式 Java/Kotlin API
框架层 Camera HAL 管理AF状态机、调用算法 QCamera2/HAL3
算法层 AF Algorithm Library 执行搜索策略、计算对焦位置 libaf.so / vendor.qti.hardware.camera.af
驱动层 Kernel Driver 控制VCM、读取马达状态 vcm驱动 / I2C

我的经验:调试AF问题时,第一步就是确认AF算法库是否被正确加载。我遇到过好几次,因为权限问题导致libaf.so没加载成功,AF直接退化成固定焦距。用logcat | grep af看一眼就能发现。

2.3 AF与ISP的交互

AF算法要工作,首先得有“眼睛”——也就是统计数据。这些数据从哪里来?从ISP来。

ISP在每一帧图像处理过程中,会计算出一组统计信息,包括但不限于:

  • 对比度统计(Focus Value):对指定ROI区域做高通滤波,得到清晰度评价值
  • 相位差统计(PDAF):从双像素或相位检测点提取相位偏移量
  • 亮度统计:用于判断场景光照条件

这些统计信息会被打包成一个结构体,通过Meta Data或者专用Buffer传递给AF算法模块。我见过最典型的坑是:ISP统计窗口配置错了,AF算法拿到的数据全是零,还以为是算法有问题。

注意:ISP统计信息的输出频率不一定跟帧率完全一致。有些平台为了省电,会降低统计信息的更新率。如果你的AF算法发现数据“卡住”了,先检查ISP的统计输出配置,别急着改算法参数。

2.4 AF与CPP的交互

AF算法算出目标位置后,怎么让镜头动起来?这就轮到CPP出场了。

CPP(Camera Post-Processor)在高通平台上负责后处理任务,同时也承担了一部分VCM控制的职责。AF算法通过CPP提供的接口,把目标位置写入VCM驱动寄存器,驱动马达移动镜头。

交互流程大致如下:

  1. AF算法计算出新的对焦位置(比如:当前镜头在200步,目标位置在350步)
  2. AF算法通过CPP的setFocusPosition()接口下发指令
  3. CPP将位置值写入VCM驱动(通常通过I2C或SPI总线)
  4. VCM驱动控制马达移动到指定位置
  5. 马达到位后,VCM驱动返回状态(成功/失败/超时)
// 伪代码示例:AF算法通过CPP下发对焦位置
void af_algorithm_process(af_stats_t *stats) {
    int32_t target_position;
    
    // 1. 根据统计数据计算目标位置
    target_position = calculate_focus_position(stats);
    
    // 2. 通过CPP接口下发
    cpp_set_focus_position(target_position);
    
    // 3. 等待马达到位(或异步回调)
    wait_for_motor_ready(50); // 最多等50ms
}

关键点:AF算法和CPP之间的通信是异步的。算法下发位置后,不会阻塞等待马达到位,而是继续处理下一帧的统计数据。马达到位后通过中断或回调通知AF算法。这个机制如果不理解,很容易写出“卡帧”的AF逻辑。

2.5 数据流与控制流总结

我把整个AF相关的数据流和控制流整理成一个表格,方便你对照理解:

步骤 数据/控制 源 目标 说明
1 RAW图像数据 Sensor ISP 原始数据输入ISP管线
2 AF统计信息 ISP AF算法 对比度/PDAF/亮度等
3 对焦位置指令 AF算法 CPP 目标位置值
4 VCM控制信号 CPP VCM驱动 I2C/SPI写入寄存器
5 马达状态反馈 VCM驱动 AF算法 到位/失败/超时

嗯,到这里你应该对高通平台的AF架构有了一个整体的认识。说白了,AF算法就是个“中间人”——从ISP拿数据,算一算,然后告诉CPP怎么动镜头。搞清楚了谁给你数据、你把数据给谁,调试起来就顺了。

避坑指南:我曾经在一个项目上花了三天时间调AF,结果发现是ISP的统计输出使能位没置起来。从那以后,我每次调试AF都先检查三个地方:ISP统计是否使能、统计窗口是否在ROI内、CPP的VCM驱动是否注册成功。这三个点检查完,80%的问题都能定位到。