You bring a MIPI CSI-2 sensor up on an embedded SoC, the driver probes cleanly, a row of /dev/video nodes appears — and every capture dies. GStreamer sticks at PREROLLING, v4l2-ctl cannot open the node, and the kernel log repeats one line: (null): mxc_isi_capture_open, No remote pad found!. Nothing is broken. On this class of SoC the sensor, CSI receiver, ISP and DMA engines are separate V4L2 subdevices, and the media controller that wires them together ships unlinked. Until you configure that graph, the capture node has no source. The sequence below fixes it: read the graph, link the pads, set a format on every pad, capture on the node that ends the chain, and script the setup so it survives a reboot.
What the failure looks like
Three symptoms, one root cause, all seen on a single board at first boot:
- An encode pipeline with
v4l2h264encnever leavesPipeline is PREROLLING, and dmesg prints(null): mxc_isi_capture_open, No remote pad found!on every attempt. -
v4l2-ctl --allon a node that exists but is absent fromv4l2-ctl --list-devicesfails withFailed to open /dev/video0: Invalid argument— the same missing-link line in dmesg. -
v4l2srcon a JPEG engine node answersDevice '/dev/video5' is not a capture device. Capabilities: 0x4208000.
All three are the same fault met at different doors: the capture hardware registered its nodes, looked for an upstream link at open, and found none. The codec and JPEG nodes are not broken; they were never capture devices.
Likely causes, most probable first
-
The media graph is unlinked. Fresh boot, nobody has run media-ctl. Pad links default to disabled, so the capture engine's sink pad has no remote pad. This accounts for most first bring-ups. Test:
media-ctl -d /dev/media0 -p, then walk the path from the sensor entity to the capture node; a link without[ENABLED]is the cause. -
You are opening a processing node. Encoders, decoders and JPEG engines register /dev/video nodes too. Test:
v4l2-ctl -d /dev/videoN -Dand read the Device Caps line; no capture flag means nothing for v4l2src to read. -
Pad formats were never set. Links exist but pads hold driver defaults that disagree downstream, so open succeeds and streaming fails or sizes clash. Test: compare the fmt lines in
media-ctl -pwith the sizes the driver lists. - The sensor entity is missing from the graph entirely. That is a probe or device-tree problem, not a linking one — fix the overlay first, following the guide to a camera loading the wrong sensor driver and the device tree devname mismatch fix.
Read the graph before you open anything
media-ctl is the V4L2 utility that sets up and configures camera-subsystem subdevices through the media controller kernel interface; its man page lists the flags used below. Start with two commands:
v4l2-ctl --list-devices
media-ctl -d /dev/media0 -p
The first maps drivers to nodes. On the example board it shows the ISI capture device at /dev/video4, JPEG engines at /dev/video5 and /dev/video6, and the codec pair at /dev/video12 and /dev/video13. The second prints the topology: entities (sensor, CSI receiver, any preprocessing block, capture DMA), their pads, and every link with its enabled flag. Vendors of these SoCs publish full topologies printed this way in their processor SDK camera-driver documentation, which is the reference to check against your own media-ctl -p output. For how a frame travels from sensor to memory on these chains, see the MIPI CSI-2 capture pipeline walkthrough.
Fix: enable links, set every format, capture at the end
- Enable each link along the path with
media-ctl -l, using the exact entity and pad numbersmedia-ctl -pprinted. A link request has the form"source entity":0 -> "sink entity":0[1]. Some graphs route through a mux or preprocessing entity — every hop needs its own enabled link; setup scripts for one SoC camera family chain sensor → mux → csi → ic_prp → ic_prpenc. - Set the format on the sensor source pad. A documented pattern from vendor media-controller configuration guides sets RAW10 on an IMX219:
media-ctl -d /dev/media0 --set-v4l2 '"imx219 1-0010":0[fmt:SRGGB10_1X10/1920x1080]'. Use a media bus code and a size your sensor driver actually lists. - Set matching formats on each downstream pad; formats do not propagate automatically on every driver. Re-run
media-ctl -pafter each change and confirm the fmt lines moved. - Capture on the node the chain ends at — the ISI capture device, /dev/video4 here, not the codec nodes beside it.
v4l2-ctl -d /dev/video4 --list-formats-extshould now list sizes. Prove the pipe with a one-frame grab:gst-launch-1.0 v4l2src device=/dev/video4 num-buffers=1 ! jpegenc ! filesink location=a.jpg. For raw Bayer from several cameras at once, continue with the six-camera v4l2-ctl capture walkthrough. - Re-run the GStreamer encode pipeline.
v4l2h264encnow leaves PREROLLING because frames arrive.
Two checks that save an afternoon
First, decode any "not a capture device" mask by hand. The board above prints Capabilities: 0x4208000 on its JPEG decoder:
0x4208000 = 0x04000000 V4L2_CAP_STREAMING
+ 0x00200000 V4L2_CAP_EXT_PIX_FORMAT
+ 0x00008000 V4L2_CAP_VIDEO_M2M
0x4208000 & 0x00000001 V4L2_CAP_VIDEO_CAPTURE = 0
Streaming, extended pixel formats, memory-to-memory — and no capture bit. Feed that node; never point v4l2src at it.
Second, check the link budget against the format you set. For the 1080p RAW10 mode from step 2:
CSI-2 packet overhead adds roughly 10-20%, so plan the link for about 0.75 Gbit/s. Two data lanes at 800 Mbit/s each carry 1.6 Gbit/s and fit with margin; two lanes at 400 Mbit/s each do not. And keep every downstream pad at or below the sensor size — the capture engine on this board refuses to enlarge, logging mxc_isi_m2m_streamon Not support upscale.
Make the setup survive a reboot
Link and format changes live in kernel memory; power cycling returns the graph to its unlinked default. Put the exact media-ctl lines in a script that runs at boot, before your application opens the device — a small systemd unit ordered before your service does it. Camera frameworks that configure the media graph themselves when the application opens the camera remove the manual step; check whether your board's stack ships one. Two habits prevent repeat failures: open only nodes whose Device Caps include the capture flag, and if the application runs in a container, pass the media node through as well — the Docker V4L2 media node guide covers that side, and the controls on the right node article explains why exposure and gain live on the sensor subdevice, not on /dev/videoN.
When to leave the media graph behind
If the inspection does not specifically need the SoC's on-chip ISP, an external area scan camera over GigE or USB3 removes the whole failure class: link, buffering and driver ship with the camera, and the capture side is an ordinary network or USB device checked with the same v4l2-ctl tests above. The camera finder filters by interface, resolution and shutter, and the configurator pairs camera, lens and light before you order. Board-level integration with a CSI sensor stays the right call when size, power or cost demands it — then the media-ctl setup above, scripted at boot, is the entire fix. Where a packaged module serves better, the shop's board-level cameras connect over USB3 or GigE rather than raw CSI lanes:
Compact cameras to build in
120 models · from $179.00The decision for each case
- No remote pad found on open or stream: the graph is unlinked. Print it, enable every link from sensor to capture node, set formats on each pad, capture at the chain end.
- "Not a capture device": wrong door. Read Device Caps, find the node with the capture bit set, point v4l2src there.
- Sensor entity missing from media-ctl -p: not a linking problem. Fix the driver or overlay first, then link.
- Works once, gone after reboot: graph state is not persisted. Script the media-ctl commands at boot — or move capture to GigE or USB3 and delete the problem.
More capture fixes like these sit on the embedded systems topic page.
Questions
Why does the node show up in v4l2-ctl --list-devices and still fail to open?
Driver binding and media-graph configuration are separate steps. The probe registers the /dev/video node, so it lists; the open path then asks the media controller for an upstream link and, finding none, returns Invalid argument and logs No remote pad found. The listing proves the driver bound, not that the pipeline is wired.
How do I tell a capture node from an encoder or decoder node?
Read Device Caps with v4l2-ctl -d /dev/videoN -D. A capture device carries V4L2_CAP_VIDEO_CAPTURE, value 0x00000001. The JPEG decoder in the worked example prints 0x4208000: streaming, extended pixel format and memory-to-memory flags, with no capture bit. Codec engines are feed-me or give-me nodes, never sources.
Do media-ctl links and formats survive a reboot?
No. Both are runtime state in the kernel; after power cycling, the graph returns to its unlinked default. Save the exact media-ctl commands in a boot script that runs before the application opens the device, or use a camera framework that configures the media graph itself when the application opens the camera.
Where do exposure and gain controls live?
On the sensor's V4L2 subdevice, not on the /dev/video capture node. List them with v4l2-ctl -d /dev/v4l-subdevN --list-ctrls and set them there. An empty control list usually means you queried the capture node or a codec node instead of the sensor entity registered under /dev/v4l-subdev.
The pipeline links but streaming fails — what sizes are legal?
Use the sizes the driver prints in v4l2-ctl --list-formats-ext, and keep every downstream pad at or below the sensor output. The capture engine in the worked example logs Not support upscale when a pad asks for more pixels than it receives, so scale down inside the pipeline or change the sensor mode instead.