写了很多Camera实战文章,但一直没系统梳理过架构。这篇补上------从V4L2框架到Pipeline/Node体系,从CRM请求管理器到IFE硬件状态机,把Camx的核心架构串一遍。理解了架构,后面的调试和开发才能有的放矢。
一、整体架构:KMD + UMD分层
高通Camera软件架构分为两层:内核态驱动(KMD) 和用户态驱动(UMD),两者通过V4L2接口通信。
| 层级 | 职责 | 核心组件 |
|---|---|---|
| UMD(用户态) | Pipeline编排、算法处理、3A | Camx Core、CHI Framework、Node |
| KMD(内核态) | 硬件控制、中断处理、DMA | CRM、IFE/VFE、CPAS、CSL |
| 通信接口 | UMD↔KMD数据交换 | V4L2 Subdevice + IOCTL |
关键设计理念:KMD只负责硬件控制,不做任何图像处理逻辑。Pipeline编排、算法决策全在UMD。这样设计的好处是KMD可以跨平台复用,而UMD可以灵活适配不同产品需求。
二、V4L2框架:Camera的通信基石
V4L2(Video4Linux2)是Linux的视频设备标准框架。高通Camera驱动基于V4L2构建,但做了大量定制。
2.1 V4L2的两层结构
V4L2是两层驱动系统:
-
顶层 videodev 模块
:注册为字符设备(major 81),提供统一的V4L2接口
-
底层 subdevice 模块
:各Camera硬件组件注册为V4L2子设备
当UMD需要操作某个Camera硬件时,通过Videodev找到对应的子设备,然后通过IOCTL发送命令。
2.2 Camera子设备清单
开机时,所有Camera硬件组件都会注册为V4L2子设备:
// 开机时子设备注册日志
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-cpas
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-isp
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-cci-driver
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-csiphy-driver
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-actuator-driver
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-sensor-driver
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-flash-dev
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-eeprom
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-ois
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-icp
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-jpeg
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-fd
CAM_INFO: CAM-CRM: cam_register_subdev: v4l2_device_register_subdev sd: cam-lrme
2.3 设备分类:实时 vs 非实时
Camera设备按功能分为两类:
| 类型 | 定义 | 设备 |
|---|---|---|
| 实时(Real-time) | 流式传输实时数据 | Sensor、Flash、IFE、OIS |
| 非实时(Non-real-time) | 内存到内存处理 | IPE、JPEG、FD、LRME、Actuator |
这个分类很重要------实时设备通过CRM同步,非实时设备不需要CRM同步。理解这一点,调试帧同步问题时就知道该查哪个链路。
三、CRM:请求管理器
CRM(Camera Request Manager)是KMD中最核心的组件,负责同步所有实时设备的请求应用。
3.1 CRM的核心职责
-
请求同步
:确保同一帧的Sensor配置、IFE配置、Flash配置同步生效
-
SOF触发
:IFE每帧产生SOF中断后通知CRM,CRM决定该帧应用哪个请求
-
请求追踪
:追踪每个请求在各设备上的就绪状态
-
错误恢复
:请求应用失败时进行重试或跳帧
-
Flush处理
:Session关闭时清理所有未完成请求
3.2 CRM的关键概念:Pipeline Delay
CRM管理请求的核心机制是Pipeline Delay(PD)。不同设备有不同的处理延迟:
// CRM Link时输出的设备Pipeline Delay信息
CAM_DBG: CAM-CRM: connected: cam-isp, id 4, delay 1, trigger 1
CAM_DBG: CAM-CRM: connected: cam-sensor, id 1, delay 2, trigger 1
CAM_DBG: CAM-CRM: connected: cam-actuator, id 3, delay 1, trigger 1
CAM_DBG: CAM-CRM: connected: cam-flash, id 2, delay 1, trigger 1
解释:
-
delay 2:Sensor,需要提前2帧配置(因为Sensor有上电+曝光延迟)
-
delay 1:IFE/Flash/Actuator,提前1帧配置
这意味着:请求N在Sensor上配置后,需要在第N+2帧的SOF时才能生效。CRM就是通过这个PD机制来同步不同设备的配置时序。
3.3 CRM请求处理流程
// CRM在SOF中断时的处理流程
// 1. IFE产生SOF中断,通知CRM
CAM_INFO: CAM-ISP: __cam_isp_ctx_notify_sof_in_activated_state: Start Notify CRM SOF frame 1
// 2. CRM工作队列被唤醒
CAM_DBG: CAM-CRM: cam_req_mgr_workq_enqueue_task: enq task pending_cnt 1
// 3. CRM查找该SOF应该应用的请求
CAM_DBG: CAM-REQ: cam_req_mgr_process_trigger: link_hdl 43010d frame_id 1, trigger 1
// 4. 检查请求就绪状态(pd_mask 6 = 0b110 = pd2+pd1就绪)
CAM_DBG: CAM-CRM: __cam_req_mgr_check_link_is_ready: SOF: idx 0 result 6 pd_mask 6
// 5. 向各设备发送应用请求
CAM_DBG: CAM-REQ: __cam_req_mgr_send_req: SEND: link_hdl: 43010d pd 2 req_id 1
CAM-REQ: cam_sensor_apply_request: Sensor update req id: 1
CAM_DBG: CAM-REQ: __cam_req_mgr_send_req: SEND: link_hdl: 43010d pd 1 req_id 1
CAM-REQ: __cam_isp_ctx_apply_req_in_activated_state: Apply request 1
日志中req_id=1:-1:0的格式表示(pd2:pd1:pd0),即pd2设备应用请求1,pd1设备跳过(-1),无pd0设备。
3.4 CRM常见错误
| 错误 | 含义 | 排查方向 |
|---|---|---|
| SOF freeze | IFE没产生SOF中断 | Sensor是否正常出流、IFE硬件是否异常 |
| Skip Frame | 请求未就绪,跳帧 | UMD未及时提交请求,查add_req日志 |
| APPLY_FAILED | 设备拒绝应用请求 | IFE状态机卡住,检查IFE日志 |
四、IFE/VFE:图像处理引擎
IFE(Image Front End)是Camera硬件的图像处理前端,负责接收Sensor输出的Raw数据并进行实时ISP处理。
4.1 IFE的硬件组成
IFE硬件包含以下主要模块:
-
CSID
:Camera Serial Interface Decoder,解码MIPI数据
-
CAMIF
:Camera Interface,接收解码后的数据
-
ISP模块
:图像信号处理(去马赛克、降噪、色彩校正等)
-
BUS_IF
:总线接口,连接后端DMA
4.2 IFE的三层架构
IFE在KMD中分为三层:
| 层级 | 职责 | 说明 |
|---|---|---|
| IFE Interface | V4L2接口层 | 注册subdevice,接收CSL IOCTL |
| IFE Context | 会话管理层 | 处理核心逻辑:SOF通知、配置缓存、Bubble检测 |
| IFE HW Manager | 硬件资源管理层 | 管理物理IFE硬件资源分配 |
4.3 IFE Context状态机
IFE Context有5个状态,描述了从初始化到工作再到释放的完整生命周期:
IFE Context状态流转:
Uninit → Available → Acquired → Ready → Activated
│ │ │ │ │
│ │ │ │ └─ 主工作状态:处理每帧请求
│ │ │ └─── 等待stream-on命令
│ │ └───── 等待初始配置 + Link
│ └──────── 初始化完成,在free pool中等待acquire
└────────── 构造完成,等硬件probe
各状态的关键行为:
-
Available
:IFE Context已初始化,在free pool中等待被acquire
-
Acquired
:已获取硬件资源,等待初始配置包和Link命令
-
Ready
:初始配置完成,等待stream-on命令
-
Activated
:主工作状态,处理SOF、配置应用、Bubble检测、BUF_DONE等
4.4 Activated状态的子状态机
进入Activated状态后,IFE还有一套子状态机,由中断驱动:
| 子状态 | 触发中断 | 行为 |
|---|---|---|
| SOF | SOF IRQ | 帧计数器+1,接收CRM的配置触发 |
| APPLIED | 配置已应用 | 等待REG_UPD或EPOCH中断 |
| EPOCH | REG_UPD IRQ | 配置已写入硬件寄存器,等待EPOCH |
| BUBBLE | EPOCH IRQ(异常) | Bubble检测,触发恢复流程 |
理解这个子状态机对调试至关重要------当你看到日志中IFE在某个子状态卡住时,就知道该查哪个中断没有按预期到来。
五、CPAS:时钟与总线管理
CPAS(Camera Power and Arbiter System)管理Camera硬件的时钟投票和总线带宽分配。
5.1 CPAS的核心功能
-
时钟投票
:各Camera模块需要工作时,通过CPAS申请时钟
-
带宽分配
:为DMA传输分配总线带宽(通过CAMNOC)
-
电源域管理
:管理Camera子系统的电源域
-
资源仲裁
:多个Camera同时使用时,仲裁资源优先级
5.2 CAMNOC总线
CAMNOC是Camera专用总线,分为三个通道:
CAMNOC通道划分:
hf1 (High-Frequency 1) → IFE实时数据传输(高带宽低延迟)
hf2 (High-Frequency 2) → IPE/JPEG非实时数据传输
sf1 (Shared-Frequency) → 配置寄存器访问(低带宽)
当出现ISP Overflow 或带宽不足的问题时,CPAS日志是关键排查入口。
5.3 开启CPAS日志
开启CPAS调试日志
adb shell "echo 0x40 > /sys/module/cam_debug_util/parameters/debug_mdl"
查看CPAS时钟投票
adb shell "cat /sys/kernel/debug/camera/cpas/cpas_info"
查看各模块带宽申请
adb shell "cat /sys/kernel/debug/camera/cpas/bw_info"
六、UMD:Pipeline与Node体系
在KMD之上,UMD负责所有Camera业务逻辑。核心概念是Pipeline 和Node。
6.1 Pipeline
Pipeline是一条处理流水线,由多个Node串联组成。一个Pipeline的典型结构:
RealtimePreview Pipeline:
SensorNode → IFENode → IPENode → OutputNode(JPEG/Preview/Video)
OfflineSnapshot Pipeline:
IFENode → IPENode → JPEGNode → OutputNode
每个Pipeline有自己的Session和Request队列。UMD通过ProcessCaptureRequest接收来自Framework的请求,分发给Pipeline处理。
6.2 Node
Node是Pipeline中的最小处理单元。每个Node有:
-
输入端口
:接收上游Node的数据(通过Fence同步)
-
处理逻辑
:ExecuteProcessRequest方法,处理一帧数据
-
输出端口
:输出处理后的数据给下游Node
-
Fence机制
:Buffer就绪通知,跨Node异步同步
6.3 UMD到KMD的调用链
一个完整的请求从Framework到硬件的调用链:
// 1. Framework发请求到Camx
camxsession.cpp: ProcessCaptureRequest()
→ 添加到请求队列,启动Job
// 2. Camx Pipeline分发请求到各Node
camxpipeline.cpp: ProcessRequest()
→ SensorNode: ApplySensorUpdate()
→ IFENode: ExecuteProcessRequest()
// 3. Node通过CSL提交硬件配置包
camxifenode.cpp: ExecuteProcessRequest()
→ CSLSubmitPacket()
// 4. KMD接收到配置包
cam_req_mgr_cb_add_req() → CRM处理
// 5. CRM在SOF时触发应用
cam_req_mgr_process_trigger()
→ __cam_isp_ctx_apply_req_in_activated_state()
// 6. 硬件配置生效,处理数据
// 7. IFE产出数据,BUF_DONE通知
__cam_isp_ctx_handle_buf_done_in_activated_state()
// 8. UMD收到Fence回调
camxnode.cpp: CSLFenceCallback()
→ SinkPortFenceSignaled()
→ 上报stream done给Framework
理解这条调用链,是排查Camera延迟和帧丢失问题的基础。当预览卡顿或帧丢失时,沿着这条链路逐段检查日志,就能定位到卡在哪个环节。
七、架构调试速查表
| 问题现象 | 排查模块 | 关键日志关键词 |
|---|---|---|
| Camera打不开 | CSL/Probe/Power | acquire_device, probe, power_on |
| 预览黑屏 | CRM/IFE | SOF, stream_on, skip_frame |
| 预览卡顿/掉帧 | CRM/UMD Pipeline | not_ready, open_req, skip |
| ISP Overflow | IFE/CPAS | overflow, csid, bus_wr_err |
| Crash | UMD/Tombstone | abort, F DEBUG, signal |
| 功耗过高 | CPAS/Clock | ahb_vote, hw_src_vote |
小结
Camx架构的核心可以浓缩为一张图:
┌─────────────────────────────────────────┐
│ Android Camera Framework │
│ (Camera2 API / CameraX) │
├─────────────────────────────────────────┤
│ UMD (Camx + CHI) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │Pipeline │→│ Node │→│ Node │ │
│ │Session │ │(IFE/IPE)│ │(JPEG等) │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │ CSL Interface │
├─────────┼──────────────────────────────────┤
│ │ V4L2 IOCTL │
│ ┌──────▼──────────────────────────────┐ │
│ │ KMD (Kernel Driver) │ │
│ │ │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ CRM │ │ IFE │ │CPAS │ │ │
│ │ │ │ │/VFE │ │ │ │ │
│ │ └──┬──┘ └──┬──┘ └─────┘ │ │
│ │ │ │ │ │
│ │ ┌──▼──┐ ┌──▼──────────┐ │ │
│ │ │Sensor│ │CSI/ISP/BUS │ │ │
│ │ │Flash │ │Hardware │ │ │
│ │ │OIS │ │ │ │ │
│ │ └─────┘ └─────────────┘ │ │
│ └──────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ Camera Hardware │
└─────────────────────────────────────────┘
理解架构是深度开发的前提。当你遇到问题时,先定位问题发生在哪一层(UMD还是KMD),再定位是哪个模块(CRM还是IFE还是CPAS),最后用对应模块的调试命令深入排查------这就是架构驱动的调试方法论。
更多Camera开发实战内容
欢迎加入知识星球「小驰成长圈」
120+ Camera工程师 · 340+ 实战内容 · 已运营1565天