02 · 摄像头这条路坑更多:漂移的设备号、默认关的链路与 STREAMON -22 本系列第 2 篇 | 2026-07 | 标签:V4L2、media-ctl、DCMIPP、IMX335、排错VPU 那条路(上一篇)坑少,摄像头这条路坑多。这一篇全是reboot 之后开不了流的连环踩坑:设备号漂移、一条默认关闭的链路、三种现象一模一样的 STREAMON -22,以及一个把采集延迟从 230ms 压到 20ms 的低级 bug。media graph 长什么样IMX335 → CSI → DCMIPP 的拓扑:imx335(2592×1944 SRGGB10) → 48020000.csi → dcmipp_input → dcmipp_main_isp ← 去马赛克 → RGB888(ISP/3A 在这层) → dcmipp_main_postproc ← 缩放 → dcmipp_main_capture ← ★ 应用真正 open 的采集口旁路实体(后面几篇会用到):实体用途dcmipp_dump_captureISP前的裸 Bayer 旁路:不能转 RGB、不能缩dcmipp_aux_captureaux 硬缩旁路 —— 第 5 篇用它做零 CPU 缩放出推理小图ISP stat / params3A 统计与参数节点用media-ctl -d /dev/mediaN -p可以通读整张图。设备节点号每次开机都会变这是整个项目里最反直觉的事实,值得单独讲透。/dev/videoN和/dev/mediaN按驱动 probe 完成顺序分配。DCMIPP / CSI / VPU谁先完成不保证(dmesg 里那堆Fixed dependency cycle(s)就是它们在互相等)。同一块板子,两次开机的实测:实体某次开机另一次开机DCMIPP dump(ISP 前裸 Bayer)/dev/video0/dev/video2DCMIPP 主路(过 ISP)/dev/video1/dev/video3DCMIPP aux(硬缩旁路)/dev/video2/dev/video4解码 vdec/dev/video5被挤走编码 venc/dev/video6被挤走DCMIPP media 节点/dev/media0/dev/media2最坏那次 DCMIPP 一口气占了video2~video6,把 vdec/venc 整个挤走。照抄写死的后果很安静:节点存在、open()成功,只是 caps 对不上 —— 报的是协商失败而不是设备不存在。查的人容易一头扎进格式配置里绕不出来。我们历史上最坏的一次:aux 打开了 dump 节点(裸 Bayer 640×480),去要 128×128 RGB3,然后花了半天研究为什么格式协商不上。解法:按实体名解析,永远别写死号# 找到 DCMIPP 的 media 节点(driver 名匹配,不看号)M$(formin/dev/media*;domedia-ctl-d$m-p2/dev/null|grep-qdriver *dcmippecho$mdone|head-1)# 按实体名要 /dev/videoNmedia-ctl-d$M-edcmipp_main_capture# ISP 主路media-ctl-d$M-edcmipp_aux_capture# aux 硬缩旁路顺带说明哪些路径天生不用管号:走 libcamerasrc 的应用:media 图由 libcamera 自己配,根本不碰/dev/video*GStreamer 的v4l2slh264enc/dec:自己按能力扫设备需要手工给路径的只剩v4l2-ctl这类工具 —— 让它们在运行时按实体名解析即可。把这条纪律扫遍所有脚本和文档之后,reboot 后开不了流这类问题从此绝迹。坑一:input → main_isp链路默认是关的⚠dcmipp_input:2 - dcmipp_main_isp:0这条 link出厂默认 disabled。不开它,main_isp就是没有输入源的孤岛,任何capture 开流都报:failed to start source subdev streaming (-22)而此时所有S_FMT和media-ctl -V全部成功—— 没有任何征兆指向链路本身。手工使能(完整步骤建议先media-ctl -p通读图):media-ctl-d$M-ldcmipp_input:2 - dcmipp_main_isp:0[1]现在运行时走 libcamerasrc 由它自配;这条只对手工排错有意义。但如果你在做自动化测试或初始化脚本,别假设任何 link 是开的。坑二:STREAMON -22 的三种软件原因现象几乎一样的-22,至少有三种软件原因,dmesg 那行不同 ——先看 dmesg 再动手:dmesg原因failed to start source subdev streaming (-22)input→main_isp链路没使能(坑一)Wrong width or height A (B expected)图里某个 capture 节点格式没钉住;报出的尺寸常来自另一条 pipemedia 图里根本没有imx335实体sensor 没 probe(才轮到查 I2C);或开机 ~14s 内跑太早、还没异步绑进来第三种我们还真遇到过硬件问题:某块板 IMX335 在 I2C0x1a无应答(i2cdetect显示--,dmesgimx335: Error reading reg 0x3912: -6),供电正常但模组无响应,定性为模组/排线/时钟/复位层面。注意顺序:三条软件原因排完,才轮到怀疑硬件。坑三:钉完格式要回读判定老流程:脚本把每个节点的格式S_FMT一遍 → 人眼比对探测输出。问题是 DCMIPP 图里有多条 pipe,你以为在给主路钉 640×480 RGB565,实际可能钉到了 aux 或 dump 上 —— S_FMT 不报错,只是没钉在你以为的那个节点上。修复思路:钉完立刻回读,程序自己判定,别靠人眼比对。后来这条原则推广成了启动自检:起进程前校验各节点格式与配置是否配套,不一致直接拒绝启动并指出该改哪一项。坑四:采集延迟 230ms → 20ms现象:v4l2src 直采这条路,端到端延迟死活在 230ms 左右压不下去。各种缓冲策略调了个遍,没用。最后定位到是一个低级 bug:初始化脚本里 sensor 名字被截断,导致格式协商走了一条完全不同的(带额外缓冲的)路径。修复后直采延迟 ~8ms。教训排序:延迟异常,先验证配置是否真的生效(结合上一条的回读判定),再怀疑管线结构。我们在这颗 bug 上先浪费的时间全花在了调队列深度上。后记:这条 ~8ms 的直采路在项目后期被整体删除了 —— 对讲场景需要 3A(自动曝光/白平衡),而裸 v4l2src 没有 3A,逆光下画面不可用。取舍过程见第 6 篇。主路只出 RGB:一个重要的限制DCMIPP ISP 主路输出RGB565/RGB888,不出 YUV。乍看是限制,实际是福利:第 1 篇说过编码器原生接受 RGB16 —— 摄像头直喂编码器,零颜色转换。这是整条采集编码链 CPU 很低的根基之一(第 5 篇有完整 CPU 账目)。遇到上游只出 X 格式时,先查下游是否原生吃 X,再上转换元件。嵌入式平台上,每一次保平安的 videoconvert 都可能是白烧的一个核的三分之一。排错清单(收藏版)# 0. probe 情况:dmesg | grep -E imx335|dcmipp 有没有实体进来# 1. 找 DCMIPP 通读拓扑,确认 input→main_isp 链路状态M$(formin/dev/media*;domedia-ctl-d$m-p2/dev/null|grep-qdriver *dcmippecho$m;done|head-1)media-ctl-d$M-p# 2. 开不了流:STREAMON 报错对应上面三行表,先看 dmesg 再动手# 3. 最小管线验证采集(VLC 打开 /tmp/cam.ts)CAM_NODE$(media-ctl-d$M-edcmipp_main_capture)gst-launch-1.0-ev4l2srcdevice$CAM_NODEio-modedmabuf!\video/x-raw,formatRGB16,width640,height480,framerate30/1!\v4l2slh264encbitrate2000000!h264parse config-interval1!mpegtsmux!filesinklocation/tmp/cam.ts下一篇:03 · 人脸识别管线优化—— 同一颗 IMX335,推理要 128×128 小图、显示要 640×480 大图,怎么把识别循环从 7.6 fps 提到 29 fps 还不占满 CPU。