V4L2 框架下 `v4l2-ctl --list-frameintervals` 调用链解析

V4L2 框架下 v4l2-ctl --list-frameintervals 调用链解析

背景

在调试 Rockchip 平台的 CIF + Sensor 驱动时,使用命令:

bash 复制代码
v4l2-ctl -d /dev/video0 --list-frameintervals width=3864,height=2192

会看到既有 Sensor 驱动 (IMX415) 的打印,又有 CIF 驱动 (rkcif) 的打印。很多人会疑惑:为什么一个命令会触发两处打印?


调用链分析

1. 用户空间

  • 命令 v4l2-ctl --list-frameintervals 对 /dev/video0 发起 ioctl:
    VIDIOC_ENUM_FRAMEINTERVALS

2. 内核第一阶段:Subdev 层

  • 在处理 VIDIOC_ENUM_FRAMEINTERVALS 时,内核会先尝试调用 subdev 的 g_frame_interval。

  • 路径:

    复制代码
    drivers/media/v4l2-core/v4l2-subdev.c
    → call_g_frame_interval()
       → sd->ops->video->g_frame_interval()
  • 此时进入 IMX415 驱动 :

    c 复制代码
    static int imx415_g_frame_interval(struct v4l2_subdev *sd,
                                       struct v4l2_subdev_frame_interval *fi)
    {
        fi->interval.numerator = 1;
        fi->interval.denominator = 30;
        printk("zzz imx415_g_frame_interval: width=%d height=%d fps=%d/%d\n",
               mode->width, mode->height,
               fi->interval.denominator, fi->interval.numerator);
        return 0;
    }
  • 所以你先看到 IMX415 的打印。

3. 内核第二阶段:Capture 层

  • 真正的 ioctl 实现是在 CIF 驱动:

    复制代码
    drivers/media/platform/rockchip/cif/capture.c
    → rkcif_enum_frameintervals()
  • 它内部再次调用:

    c 复制代码
    ret = v4l2_subdev_call(sensor->sd, video, g_frame_interval, &fi);
  • 但此处的 sensor->sd 指向的是 rockchip-mipi-csi2 bridge,而不是 IMX415。

  • 因为 CSI2 bridge 没有实现 g_frame_interval,所以返回 -ENOIOCTLCMD,CIF fallback 到默认 30fps。

  • 所以你又看到 CIF 的打印 :

    复制代码
    rkcif_enum_frameintervals: sensor->sd name=rockchip-mipi-csi2 ...
    sensor not implements g_frame_interval, use default 30fps

为什么会有两次打印

  • 一次 ioctl → 用户空间只调用了 VIDIOC_ENUM_FRAMEINTERVALS。
  • 两次打印 → 内核处理时分成两个阶段:
    1. 先调用 subdev 的 g_frame_interval → 打印 IMX415。
    2. 再调用 capture 驱动的 enum_frameintervals → 打印 CIF。

问题根因

  • CIF 驱动的 active_sensor->sd 指向的是 CSI2 bridge,而不是 IMX415。
  • 所以 CIF 层拿不到 IMX415 的真实 fps,只能 fallback 到默认 30fps。

调试建议

  1. 在 rkcif_enum_frameintervals() 打印:

    c 复制代码
    v4l2_info(&dev->v4l2_dev,
        "zzz %s: sensor->sd name=%s ops=%p video_ops=%p g_frame_interval=%p\n",
        __func__,
        sensor->sd->name,
        sensor->sd->ops,
        sensor->sd->ops ? sensor->sd->ops->video : NULL,
        (sensor->sd->ops && sensor->sd->ops->video) ?
            sensor->sd->ops->video->g_frame_interval : NULL);

    确认 active_sensor->sd 是否真的是 IMX415。

  2. 检查 media graph link,确认 CIF 是否直接绑定到 sensor,而不是 CSI2 bridge。

  3. 如果需要 fps 信息,应当在 CIF 层透传到 sensor,而不是停在 bridge。


总结

  • v4l2-ctl --list-frameintervals 会触发 一次 ioctl,但在内核里分成两个阶段调用。
  • 所以你会看到 先打印 IMX415 (subdev) ,再打印 CIF (capture)。
  • 根因是 CIF 的 active_sensor 指向了 CSI2 bridge,没有实现 g_frame_interval,导致 fallback 到默认 30fps。
相关推荐
叼烟扛炮10 小时前
Linux 学习笔记(四十一):TCP 并发演进——从单进程到多线程服务器
linux·运维·服务器·网络·笔记·学习·tcp/ip
ynchyong10 小时前
Linux 有两个 “版本“
linux·发行版·内核版本
叼烟扛炮10 小时前
Linux 学习笔记(四十四):HTTP 协议解析与极简 Web 服务器实战
linux·服务器·学习
叼烟扛炮10 小时前
Linux 学习笔记(四十三):网络编程进阶——自定义协议解决 TCP 粘包与守护进程
linux·开发语言·网络·笔记·tcp/ip
Escalating_xu11 小时前
【Linux 网络编程】DNS 与 ICMP:从域名解析到 ping、traceroute,把“网络通不通”问清楚
linux·网络·php
如若12312 小时前
Windows SSH + Headscale/Tailscale 组网及免密登录完整配置教程
运维·windows·ubuntu·ssh·内网穿透
一枕槐安48713 小时前
大模型限流、重试、超时处理:API 调用健壮性方案
linux·服务器·php·大模型api·指数退避·限流控制·超时预算
西索斯coding13 小时前
gpt-image-2.5-sunburst 和 gemini-3.1-flash-image 差多少?60 组项目素材的成功成本评测框架
java·linux·gpt·ai
箓维13 小时前
应用层协议基础_序列化与反序列化
linux
wuminyu13 小时前
Java字节码学习总结:字节码如何加载、解析和执行
java·linux·c语言·jvm·c++