3. Media Controller框架

Media Controller(MC)是 Linux 内核中用于管理复杂多媒体设备数据流的框架。在 ISP Pipeline 中,一个 ISP 设备通常包含多个硬件模块(如 CSI 接收器、ISP 前端、统计处理单元、缩放器),这些模块通过内部硬件通路连接。V4L2 的传统接口只能描述单个视频设备节点,无法表达模块间的内部连接关系。Media Controller 通过 entity(实体)、pad(垫片) 和 link(连接) 三个核心抽象,将 ISP 内部的硬件拓扑暴露给用户空间,使驱动开发者能够精确控制数据流路径。

3.1 Media Controller 核心架构

Media Controller 位于 V4L2 框架之下,为 V4L2 子设备提供拓扑管理能力。其核心数据结构定义在 include/media/media-device.h 和 include/media/media-entity.h 中。

核心概念 数据结构 描述
Media Device struct media_device 代表整个多媒体设备,管理所有 entity 和 link,提供设备节点 /dev/media0
Entity struct media_entity 代表一个硬件功能模块(如 sensor、ISP core、scaler),可包含多个 pad
Pad struct media_pad 实体上的数据输入/输出端口,分为 source pad(源端)和 sink pad(接收端)
Link struct media_link 连接两个 pad 的数据通路,可配置为 enable/disable 状态
架构要点: Media Controller 不负责数据传输本身,只负责描述“谁可以连接到谁”。实际数据流仍通过 V4L2 的 buffer 队列和 subdev 操作完成。MC 提供了拓扑发现和链路控制能力,是 ISP Pipeline 配置的“地图”。

3.2 Entity / Pad / Link 模型详解

3.2.1 Entity(实体)

每个 entity 对应 ISP 内部一个独立的硬件处理单元。在驱动中,entity 通常与 V4L2 subdev 绑定。例如,一个 ISP 驱动可能注册以下 entity:

  • Sensor entity:图像传感器,通常只有 1 个 source pad
  • CSI-2 Receiver entity:MIPI CSI-2 接收器,1 个 sink pad + 1 个 source pad
  • ISP Frontend entity:Bayer 处理、黑电平校正、去噪,1 sink + 1 source
  • Statistics entity:3A 统计信息输出,1 sink pad(仅输出元数据)
  • Scaler entity:图像缩放,1 sink + 1 source

3.2.2 Pad(垫片)

Pad 是 entity 的数据接口,分为两种类型:

  • MEDIA_PAD_FL_SINK:接收数据的输入端口
  • MEDIA_PAD_FL_SOURCE:发送数据的输出端口

一个 entity 可以有多个 pad。例如,ISP 统计 entity 可能有一个 sink pad 接收图像数据,同时有多个 source pad 分别输出不同统计结果。

3.2.3 Link(连接)

Link 定义了两个 pad 之间的连接关系。Link 的状态可以通过 MEDIA_LNK_FL_ENABLED 标志控制。在 ISP 中,某些 link 是硬件固定的(不可更改),某些是软件可配置的(如选择不同的 sensor 输入源)。

驱动开发提示: 在 probe 阶段,驱动需要调用 media_create_pad_link() 建立 entity 之间的默认连接。用户空间通过 MEDIA_IOC_SETUP_LINK ioctl 在运行时动态切换链路,实现 ISP 数据流重配置。

3.3 拓扑结构建立

ISP Pipeline 的拓扑结构在驱动初始化时建立,通常分为三个步骤:

  1. 注册 Media Device:调用 media_device_register(),创建 /dev/mediaX 节点
  2. 注册 Entity:为每个硬件模块调用 media_entity_pads_init() 初始化 pad 数组,然后通过 V4L2 subdev 注册时自动关联 entity
  3. 建立 Link:调用 media_create_pad_link() 连接 source pad 到 sink pad

以下是一个典型的 ISP 拓扑建立代码片段:

// 定义 entity 和 pad
static struct media_pad sensor_pads[] = {
    { .flags = MEDIA_PAD_FL_SOURCE }
};
static struct media_pad isp_frontend_pads[] = {
    { .flags = MEDIA_PAD_FL_SINK },
    { .flags = MEDIA_PAD_FL_SOURCE }
};

// 在 probe 函数中建立拓扑
media_device_register(&isp->media_dev);

// sensor -> ISP frontend
media_create_pad_link(
    &sensor->sd.entity, 0,   // sensor source pad 0
    &isp_fe->sd.entity, 0,   // ISP frontend sink pad 0
    MEDIA_LNK_FL_ENABLED
);

// ISP frontend -> scaler
media_create_pad_link(
    &isp_fe->sd.entity, 1,   // ISP frontend source pad 1
    &scaler->sd.entity, 0,   // scaler sink pad 0
    MEDIA_LNK_FL_ENABLED
);
注意事项: Link 的建立顺序必须与硬件数据流方向一致。如果硬件支持多路复用(如多个 sensor 共享同一个 CSI 接收器),需要创建多个 link 但只 enable 当前活跃的那一条。错误的 link 配置可能导致系统崩溃或数据错乱。

3.4 与 V4L2 的协同工作

Media Controller 与 V4L2 的协同是 ISP 驱动开发的核心难点。两者通过 V4L2 subdev 和 video device node 实现交互。

组件 V4L2 角色 Media Controller 角色
Sensor V4L2 subdev,提供 s_power、s_fmt 操作 Entity,暴露 source pad
ISP Core V4L2 subdev,提供 s_fmt、s_ctrl 操作 Entity,暴露 sink + source pad
Video Capture V4L2 video device,提供 VIDIOC_QBUF、VIDIOC_DQBUF Entity,通常作为 pipeline 的末端

协同工作流程如下:

  1. 拓扑发现:用户空间通过 MEDIA_IOC_ENUM_ENTITIES 和 MEDIA_IOC_ENUM_LINKS 获取 ISP 内部连接图
  2. Pipeline 配置:通过 MEDIA_IOC_SETUP_LINK 启用/禁用特定数据通路
  3. 格式协商:V4L2 subdev 的 pad ops(如 get_fmt、set_fmt)在 entity 之间传递格式信息,确保 pipeline 各阶段格式一致
  4. 数据流启动:V4L2 video device 调用 streamon,触发 subdev 的 s_stream 回调,沿 pipeline 逐级启动硬件
关键协同机制: V4L2 subdev 的 pad ops 是 MC 与 V4L2 的桥梁。驱动在 set_fmt 回调中不仅要更新当前 subdev 的格式,还需要通过 media_pipeline 通知上下游 entity 进行格式同步。这种“链式传播”保证了 ISP pipeline 中每个模块的配置一致性。

3.5 ISP Pipeline 拓扑结构图

下图展示了一个典型的 ISP Pipeline 拓扑结构,包含 sensor、CSI 接收器、ISP 前端、统计模块和缩放器:

ISP Pipeline Media Controller 拓扑结构 ISP Pipeline Media Controller 拓扑结构 Sensor entity 0 CSI-2 Receiver entity 1 ISP Frontend entity 2 Statistics entity 3 Scaler entity 4 src0 sink0 src0 sink0 src0 src1 sink0 sink0 link 0 (ENABLED) link 1 (ENABLED) link 2 (ENABLED) link 3 (DISABLED) 拓扑说明: 1. 实线箭头表示当前 ENABLED 的数据通路:Sensor → CSI → ISP → Scaler 2. 虚线箭头表示 DISABLED 的统计通路,用户空间可通过 MEDIA_IOC_SETUP_LINK 启用 3. 每个 entity 的 pad 编号(sink0/src0)与驱动中 media_pad 数组索引对应 4. 格式协商沿 ENABLED link 传播,确保 pipeline 各阶段格式一致

3.6 用户空间拓扑操作示例

用户空间通过 media-ctl 工具或直接调用 ioctl 操作拓扑。以下是一个典型的 ISP pipeline 配置流程:

# 1. 枚举所有 entity
media-ctl -d /dev/media0 -e

# 2. 查看当前拓扑
media-ctl -d /dev/media0 -p

# 3. 设置 sensor 格式(通过 V4L2 subdev)
v4l2-ctl -d /dev/v4l-subdev0 --set-fmt-video=width=1920,height=1080,code=SRGGB10_1X10

# 4. 启用统计链路(将 link 3 从 DISABLED 改为 ENABLED)
media-ctl -d /dev/media0 -l '"ISP Frontend":1 -> "Statistics":0 [1]'

# 5. 设置 video 节点格式并开始采集
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat=NV12
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=100
调试技巧: 使用 media-ctl -p 打印完整拓扑时,注意检查每个 link 的 [ENABLED] 或 [DISABLED] 状态。如果采集无数据输出,首先确认从 sensor 到 video node 的整条链路是否全部为 ENABLED 状态。常见错误是统计链路意外使能导致 ISP 内部带宽分配异常。

3.7 本章小结