2. v4l2-compliance 工具介绍

v4l2-compliance 是 Linux 内核 V4L2 框架的官方合规性测试工具,由内核社区维护,用于验证 V4L2 设备驱动对 V4L2 规范(specification)的符合程度。它通过调用一系列 ioctl 接口,检查驱动在格式协商、缓冲区管理、流控制、裁剪/缩放、控制属性等方面的行为是否与内核期望一致。本章将深入分析该工具的源码结构、编译方法以及核心命令行参数的使用方式。

2.1 工具源码结构

v4l2-compliance 的源码位于 Linux 内核源码树的 tools/testing/selftests/media/v4l2-compliance/ 目录下,也可从 v4l-utils 仓库 独立获取。其核心源码文件及职责如下表所示:

源文件 职责说明
v4l2-compliance.cpp 主入口文件,解析命令行参数,调度测试流程,输出测试报告
v4l2-test-debug.cpp 测试 VIDIOC_LOG_STATUS、VIDIOC_DBG_G/S_REGISTER 等调试 ioctl
v4l2-test-input-output.cpp 测试输入/输出(input/output)枚举、查询、切换相关 ioctl
v4l2-test-audio.cpp 测试音频输入/输出 ioctl(VIDIOC_ENUMAUDIO、VIDIOC_G/S_AUDIO 等)
v4l2-test-tuner.cpp 测试调谐器(tuner)与调制器(modulator)相关 ioctl
v4l2-test-formats.cpp 测试格式枚举、获取、设置(VIDIOC_ENUM_FMT、VIDIOC_G/S_FMT、VIDIOC_TRY_FMT)
v4l2-test-buffers.cpp 测试缓冲区申请、入队、出队、流控制(VIDIOC_REQBUFS、VIDIOC_QBUF/DQBUF、VIDIOC_STREAMON/OFF)
v4l2-test-controls.cpp 测试控制属性(controls)的枚举、查询、获取、设置、事件订阅
v4l2-test-selection.cpp 测试裁剪/缩放(VIDIOC_G/S_SELECTION)与 compose 区域
v4l2-test-ioctl.cpp 测试通用 ioctl 调用(VIDIOC_QUERYCAP、VIDIOC_ENUM_FRAMESIZES、VIDIOC_ENUM_FRAMEINTERVALS 等)
关键设计原则: 每个测试文件对应 V4L2 规范中的一个功能域,测试用例按 ioctl 分组,每个测试函数返回 0(通过)、1(失败)或 -1(跳过/不适用)。这种模块化设计便于开发者快速定位驱动在哪个功能域存在合规性问题。

下图展示了 v4l2-compliance 的源码模块调用关系与测试流程:

v4l2-compliance 源码模块调用关系图 v4l2-compliance.cpp test-debug.cpp test-input-output.cpp test-audio.cpp test-tuner.cpp test-formats.cpp test-buffers.cpp test-controls.cpp test-selection.cpp test-ioctl.cpp 测试报告输出 模块化设计要点 每个测试文件独立编译为 .o 目标文件,通过主程序统一调度 测试失败时返回非零值,主程序汇总后输出 PASS/FAIL/SKIP 统计

2.2 编译方法

v4l2-compliance 的编译有两种主流方式:作为内核 selftests 的一部分编译,或从 v4l-utils 独立编译。推荐使用后者,因为独立编译更灵活且不依赖完整内核源码树。

2.2.1 从 v4l-utils 仓库编译(推荐)

# 克隆 v4l-utils 仓库
git clone https://git.linuxtv.org/v4l-utils.git
cd v4l-utils

# 配置编译环境(需要 meson 和 ninja)
meson setup builddir
cd builddir

# 编译 v4l2-compliance(只编译该工具,不编译其他组件)
ninja v4l2-compliance

# 编译完成后,二进制位于 builddir/utils/v4l2-compliance
./utils/v4l2-compliance --help
编译依赖: 需要安装 meson(≥0.55)、ninja、libudev-dev、libv4l-dev。如果只需要 v4l2-compliance,可以在 meson setup 时添加 -Dutils=enabled -Dlibv4l=false -Dv4l-utils=false 来减少编译时间。

2.2.2 作为内核 selftests 编译

# 进入内核源码树
cd /path/to/linux-kernel

# 配置 selftests
make -C tools/testing/selftests TARGETS=media

# 单独编译 v4l2-compliance
make -C tools/testing/selftests/media/v4l2-compliance

# 编译产物位于 tools/testing/selftests/media/v4l2-compliance/
ls -l tools/testing/selftests/media/v4l2-compliance/v4l2-compliance
注意: 内核 selftests 方式编译出的 v4l2-compliance 版本与内核版本绑定。如果测试较新内核的驱动,建议使用 v4l-utils 仓库的最新 master 分支,因为该仓库会及时跟进 V4L2 规范变更。

2.3 基本命令行参数详解

v4l2-compliance 提供了丰富的命令行参数来控制测试范围、设备选择、输出格式等。以下是最核心的五个参数:-s、-m、-d、-c、-f。

参数 全称 功能说明 典型用法
-s --stream 启用流式测试(streaming test),包括缓冲区申请、入队/出队、STREAMON/OFF 等 v4l2-compliance -s
-m --multiple 多平面(multi-planar)测试模式,针对 MPLANE 类型的视频设备 v4l2-compliance -m
-d --device 指定要测试的 V4L2 设备节点路径 v4l2-compliance -d /dev/video0
-c --color 启用彩色输出,使 PASS/FAIL/SKIP 结果更易区分 v4l2-compliance -c
-f --force 强制测试所有用例,即使某些前置条件不满足(如无视频输入) v4l2-compliance -f

2.3.1 -s(流式测试)

默认情况下,v4l2-compliance 只执行静态 ioctl 测试(如 QUERYCAP、ENUM_FMT、G/S_FMT 等),不涉及数据流。添加 -s 参数后,工具会执行完整的流式测试流程:

  1. REQBUFS: 申请缓冲区(默认 4 个缓冲区)。
  2. QUERYBUF: 查询每个缓冲区的状态和内存信息。
  3. QBUF: 将所有缓冲区入队到驱动。
  4. STREAMON: 启动视频流。
  5. DQBUF: 出队缓冲区(等待驱动填充数据)。
  6. STREAMOFF: 停止视频流。
  7. REQBUFS(0): 释放所有缓冲区。
测试意义: 流式测试是验证驱动数据路径是否完整的关键。如果驱动在 STREAMON 后无法产生数据,或 DQBUF 超时,-s 测试会直接报 FAIL。对于 capture 设备,建议始终使用 -s 进行完整测试。

2.3.2 -m(多平面模式)

V4L2 支持单平面(SINGLE_PLANE)和多平面(MULTI_PLANE)两种缓冲区模型。多平面模式用于 YUV 分量分离存储或元数据附加等场景。使用 -m 参数时,v4l2-compliance 会:

  • 在 REQBUFS 时使用 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE 或 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE。
  • 在 QBUF/DQBUF 时使用 struct v4l2_plane 数组。
  • 检查驱动是否正确处理 V4L2_BUF_FLAG_MULTIPLANE 标志。
何时使用: 如果被测设备是 M2M(memory-to-memory)或支持 NV12/NV16 等半平面格式,建议同时测试单平面和多平面两种模式。先不带 -m 跑一次,再带 -m 跑一次,对比结果。

2.3.3 -d(指定设备)

默认情况下,v4l2-compliance 会扫描 /dev/video0 到 /dev/video63 以及 /dev/v4l-subdev* 等所有 V4L2 设备节点。使用 -d 可以精确指定单个设备:

# 测试 /dev/video2
v4l2-compliance -d /dev/video2 -s

# 测试 /dev/v4l-subdev1(子设备)
v4l2-compliance -d /dev/v4l-subdev1
权限注意: 测试需要 root 权限或对设备节点有读写权限。如果遇到 Permission denied,使用 sudo 或以 root 身份运行。

2.3.4 -c(彩色输出)

添加 -c 参数后,测试结果会使用 ANSI 转义码着色:

  • PASS: 绿色高亮
  • FAIL: 红色高亮
  • SKIP: 黄色高亮

在终端中,这能显著提升测试结果的可读性,尤其是在大量测试用例输出时。

2.3.5 -f(强制测试)

某些测试用例需要前置条件(如设备必须有视频输入、必须有音频输入等)。默认情况下,如果前置条件不满足,v4l2-compliance 会跳过该测试。使用 -f 后,即使前置条件不满足,也会执行测试并报告 FAIL(如果驱动返回错误)或 PASS(如果驱动优雅地返回 EINVAL 或 ENOTTY)。

使用场景: 在驱动开发阶段,使用 -f 可以确保所有 ioctl 都被调用到,即使某些功能尚未实现。这有助于发现驱动是否在未实现的功能上返回了错误的错误码(如返回 EIO 而不是 ENOTTY)。

下图展示了 v4l2-compliance 命令行参数与测试流程的对应关系:

v4l2-compliance 命令行参数与测试流程 v4l2-compliance -d /dev/video0 -s -c 参数解析阶段 -d: 指定设备节点 -s: 启用流式测试 -c: 启用彩色输出 测试执行:静态 ioctl + 流式 ioctl 测试报告(彩色 PASS/FAIL/SKIP)

2.4 参数组合使用示例

在实际测试中,通常需要组合多个参数来覆盖完整的测试场景。以下是一些典型组合:

命令 适用场景 说明
v4l2-compliance -d /dev/video0 -s -c 单摄像头设备完整测试 指定设备、启用流式测试、彩色输出
v4l2-compliance -d /dev/video0 -s -m -c 多平面摄像头设备测试 在单平面基础上增加多平面模式
v4l2-compliance -d /dev/video0 -f -c 驱动开发阶段强制测试 即使前置条件不满足也执行所有用例
v4l2-compliance -s -c 2>&1 | tee test.log 全设备扫描并保存日志 扫描所有设备,结果同时输出到终端和文件
最佳实践: 在驱动提交内核主线前,建议执行以下完整测试序列:
1. v4l2-compliance -d /dev/videoX -s -c(单平面流式测试)
2. v4l2-compliance -d /dev/videoX -s -m -c(多平面流式测试)
3. v4l2-compliance -d /dev/videoX -f -c(强制测试,检查错误码合规性)
所有测试必须返回 0 FAIL,否则驱动存在合规性问题。

2.5 测试输出解读

v4l2-compliance 的输出格式清晰,每行包含测试名称、测试结果和简要说明。以下是一个典型输出片段:

# v4l2-compliance -d /dev/video0 -s -c

v4l2-compliance SHA: 1234567890ab, 64 bits, 64-bit time_t

Compliance test for device /dev/video0:

Driver Info:
        Driver name      : uvcvideo
        Card type        : USB Camera
        Bus info         : usb-0000:00:14.0-1
        Driver version   : 6.1.0
        Capabilities     : 0x84a00001
                Video Capture
                Streaming
                Extended Pix Format
                Device Capabilities
        Required ioctls:
                VIDIOC_QUERYCAP: OK

        ...

        Streaming ioctls:
                VIDIOC_REQBUFS: OK
                VIDIOC_QUERYBUF: OK
                VIDIOC_QBUF: OK
                VIDIOC_DQBUF: OK
                VIDIOC_STREAMON: OK
                VIDIOC_STREAMOFF: OK

        ...

Total for /dev/video0: 45 PASS, 0 FAIL, 3 SKIP
结果解读: PASS 表示测试通过;FAIL 表示驱动行为与 V4L2 规范不符,需要修复;SKIP 表示该测试因前置条件不满足(如设备不支持该功能)而被跳过。理想情况下,FAIL 应为 0,SKIP 数量应合理(取决于设备功能集)。