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。
相关推荐
一叶龙洲3 小时前
wslg打开Ubuntu24.04默认打开图形界面
linux·服务器·数据库·ubuntu
敖行客 Allthinker5 小时前
Parallels Ubuntu虚拟机项目如何让手机访问?完整解决方案
linux·运维·ubuntu
keyipatience6 小时前
线程栈与TLS和线程互斥
java·linux·服务器·开发语言·ubuntu
j7~6 小时前
【Linux】二十二.《Linux 信号机制完全指南:表示、捕捉与处理》
linux·信号处理·volatile·可入重函数·保存信号
观山岳五楼7 小时前
Ubuntu 24 怎么使用Ubuntu 20 的镜像源
linux·运维·ubuntu
m0_715646768 小时前
20260720
linux·arm
寒晓星8 小时前
[linux]线程及多线程
linux·运维
辰痕~8 小时前
物理机装Linux操作系统(Ubuntu为例)
linux·ubuntu
国服第二切图仔10 小时前
13其他工具 - Skill/LSP/Sleep等
linux·运维·里氏替换原则
就不掉头发10 小时前
计算机的虚拟内存
linux·服务器·windows