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 驱动 :
cstatic 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() -
它内部再次调用:
cret = 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。 - 两次打印 → 内核处理时分成两个阶段:
- 先调用 subdev 的 g_frame_interval → 打印 IMX415。
- 再调用 capture 驱动的 enum_frameintervals → 打印 CIF。
问题根因
- CIF 驱动的
active_sensor->sd指向的是 CSI2 bridge,而不是 IMX415。 - 所以 CIF 层拿不到 IMX415 的真实 fps,只能 fallback 到默认 30fps。
调试建议
-
在
rkcif_enum_frameintervals()打印:cv4l2_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。 -
检查 media graph link,确认 CIF 是否直接绑定到 sensor,而不是 CSI2 bridge。
-
如果需要 fps 信息,应当在 CIF 层透传到 sensor,而不是停在 bridge。
总结
v4l2-ctl --list-frameintervals会触发 一次 ioctl,但在内核里分成两个阶段调用。- 所以你会看到 先打印 IMX415 (subdev) ,再打印 CIF (capture)。
- 根因是 CIF 的
active_sensor指向了 CSI2 bridge,没有实现g_frame_interval,导致 fallback 到默认 30fps。