# V4L2 inventory findings — fresnel 2026-05-07

Companion to [`v4l2_inventory.txt`](v4l2_inventory.txt) (raw `v4l2-ctl` / `media-ctl` / sysfs output captured 2026-05-07T22:34 CEST).

## Verified facts

### Two decode blocks, six v4l2 nodes total

| Node | Driver | DT compatible | Function |
|---|---|---|---|
| `/dev/video0` | `rockchip-rga` | `rockchip,rk3399-rga` | RGA scaler/converter (out of scope) |
| `/dev/video1` | `uvcvideo` | — | USB camera capture |
| `/dev/video2` | `uvcvideo` | — | USB camera metadata |
| `/dev/video3` | `rkvdec` | `rockchip,rk3399-vdec` | Stateless decoder (3 codecs) |
| `/dev/video4` | `hantro-vpu` | `rockchip,rk3399-vpu` | Encoder (JPEG only) |
| `/dev/video5` | `hantro-vpu` | `rockchip,rk3399-vpu` | Stateless decoder (2 codecs) |

`/dev/video4` and `/dev/video5` share the parent platform device `ff650000.video-codec` — same hantro IP, two function instances (enc + dec).

### Decoder codec surface (authoritative — from `--list-formats-out`)

**`/dev/video3` (rkvdec)** — three codecs:

```
[0]: 'S265' (HEVC Parsed Slice Data, compressed)
[1]: 'S264' (H.264 Parsed Slice Data, compressed)
[2]: 'VP9F' (VP9 Frame, compressed)
```

CAPTURE: NV12 only.

**`/dev/video5` (hantro-vpu-dec)** — two codecs:

```
[0]: 'MG2S' (MPEG-2 Parsed Slice Data, compressed)
[1]: 'VP8F' (VP8 Frame, compressed)
```

CAPTURE: NV12 only.

### Profile/level menus (from `--list-ctrls-menus`)

rkvdec exposes:

- **H.264 profiles**: Constrained Baseline, Main, **High**, High 10, High 422, High 10 Intra, High 422 Intra. Levels 1 through 5.1 (16 entries). Note: 10-bit/422 entries listed are kernel-driver enumeration, not necessarily silicon-supported — the rkvdec driver may reject these at request submission.
- **HEVC profiles**: Main, Main Still Picture, **Main 10**. Levels 1 through 5.1 (9 entries).
- **VP9 profile**: 0 only (8-bit 4:2:0). No profile-2 (10-bit), profile-1 (4:4:4), or profile-3 listed.

hantro-vpu-dec exposes **no** profile/level menus — MPEG-2 and VP8 don't need them.

### Stateless control payloads

rkvdec accepts:

- H.264: `H264_DECODE_MODE` (Frame-Based), `H264_START_CODE` (Annex B), SPS, PPS, scaling matrix, decode params.
- HEVC: `HEVC_DECODE_MODE` (Frame-Based), `HEVC_START_CODE` (Annex B), SPS, PPS, slice params (dynamic-array, max 600 elems), scaling matrix, decode params.
- VP9: `VP9_FRAME` (frame decode params), `VP9_PROBABILITIES_UPDATES` (control type 260).

hantro-vpu-dec accepts:

- VP8: `VP8_FRAME` (frame decode params).
- MPEG-2: `MPEG_2_SEQUENCE_HEADER`, `MPEG_2_PICTURE_HEADER`, `MPEG_2_QUANTISATION_MATRICES`.

Both drivers report `value=unsupported payload type` from `v4l2-ctl` for compound controls — normal; v4l2-ctl can't serialize them, the kernel ABI uses `VIDIOC_S_EXT_CTRLS` with `V4L2_CTRL_WHICH_REQUEST_VAL`.

### Media controller topology

- `/dev/media0` → uvcvideo (USB cam), entities 1/4/8/11/14.
- `/dev/media1` → rkvdec, simple source→proc→sink (3 entities).
- `/dev/media2` → hantro-vpu, holds **both** enc and dec sub-pipelines under one media device. Decode sub-pipeline: entities 15/17/20 (`rockchip,rk3399-vpu-dec-source` → `-proc` → `-sink`). Encode sub-pipeline: entities 1/3/6.

For per-codec `media_path` resolution the libva backend can use either fixed device-node paths (simple) or media-controller graph traversal (matches Bootlin sunxi-cedrus pattern). Phase 4 design decision.

## Corrections required in locked Phase 0 docs

`phase0_findings.md` lines 26–28 and `README.md:24–28` claim hantro-vpu-dec on RK3399 supports H.264 (`V4L2_PIX_FMT_H264_SLICE`). **This is wrong on the running kernel `6.19.9-99-eos-arm`.** The actual surface is MPEG-2 + VP8 only.

Implications:

1. **Open Question #2 from `phase0_findings.md` is null** — there's no two-block H.264 routing decision to make. H.264 only goes to rkvdec on RK3399. The libva backend's device-selection logic for H.264 has exactly one valid bind target.
2. The "test cells per codec" sentence ("Two test cells per codec: rkvdec-bound H.264 and hantro-vpu-dec-bound H.264.") should be reduced to one cell.
3. Codec scope as locked stays correct in **count** — five codecs, just routed differently:
   - rkvdec: H.264, HEVC, VP9
   - hantro-vpu-dec: MPEG-2, VP8

These corrections should land as a follow-up commit on this campaign repo. Not done in this file to keep evidence and source-of-truth separable.

## Why the doc was wrong

Likely carryover from RK3568 (ohm) hantro, which does support H.264 (DT compatible `rockchip,rk3568-vpu`). The RK3399 hantro IP / kernel variant in `drivers/media/platform/verisilicon/` registers a different codec list. The phase0_findings.md table was written without empirical enumeration on this kernel.

## Gaps left for Phase 1+

- Resolution range per codec — not enumerated by `v4l2-ctl --list-formats-out` directly. Will need `v4l2-ctl --try-fmt-out-mplane` probes against rkvdec to find min/max width/height per codec, especially HEVC (4K+ would matter for VP9 but the panel is 1080p so probably moot).
- Per-codec slice-mode vs. frame-mode capability — both decoders advertise frame-based only (`*_DECODE_MODE menu min=1 max=1 default=1 (Frame-Based)`). This matches the libva-v4l2-request-fourier fork's slice-buffer accumulation pattern from libva-multiplanar iter4.
- Bit-depth limits — `H264_HIGH_10` profile is enumerated on rkvdec but RK3399 silicon doesn't do 10-bit H.264. Test will reveal whether the driver rejects 10-bit submission or just silently produces garbage.
