Video decoding and rendering follow-up
Physical board, 2026-09-22 America/Chicago (2026-09-23 UTC), running the
persistent Wi-Fi image. These are temporary
probe packages from nix/video-probe.nix, not an installed default video app.
Audio is disabled throughout. Big Buck Bunny © 2008 Blender Foundation,
CC BY 3.0.
Hardware decoder
The live capability query identifies /dev/video0 as
MVX/Linlon, V4L2 memory-to-memory, with H.264 compressed input and raw YUV
output. Listing other formats is not proof that those codecs work. The small
query binary was first built against a different cross-libc path; invoking it
with the board’s installed compatible loader resolved that host-build mismatch.
The rebuilt FFmpeg enables withV4l2M2m = true and h264_v4l2m2m explicitly.
The decoder flag is -c:v h264_v4l2m2m; mpv selects it with
--vd=h264_v4l2m2m. --hwdec=no in the trial disables mpv’s separate automatic
hwaccel negotiation; it does not override this explicit V4L2 decoder selection.
Logs confirm the selected decoder opens /dev/video0 using driver mvx.
Packages:
- mpv:
/nix/store/dpylynz13fl5kmkfksnvwgv9arqy0hpr-mpv-riscv64-unknown-linux-gnu-0.41.0 - FFmpeg:
/nix/store/vr4r48cj2wlbzsqmkvgp35chngjidk3z-ffmpeg-riscv64-unknown-linux-gnu-9.0.1-bin
The driver already includes vendor codec microcode in the kernel. See the source and firmware audit; this is not a blob-free path or evidence of GPU rendering.
Decode-only comparison
A local fragmented-MP4 sample concatenated the initialization segment and
segments 12–15 of bbb_30fps_640x360_1000k from
https://dash.akamaized.net/akamai/bbb_30fps/. It contains the same public BBB
representation used for the network trial. Local input removes network time;
null output removes scaling and display. Each invocation stopped at 300 output
frames, with -debug_ts -benchmark, no input seek, and no duration-based stop.
These are single bounded observations, not statistical benchmark estimates.
| Decoder | Output frames | Wall time | User + system CPU time | Reported rate |
|---|---|---|---|---|
| Software H.264 | 300 | 3.873 s | 3.626 s | 77 fps |
| MVX H.264 | 300 | 1.259 s | 0.469 s | 239 fps |
Both completed successfully with zero reported decode errors. Those rates measure decode to a null sink, not on-screen frame rate.
MVX’s timestamps are not yet trustworthy: the captured sequence starts with repeated zeros, whereas software starts 0,1,2,3,4 at time base 1/30. The excerpt contains 292 parseable timestamps and is not a complete frame-index map. The hardware run reports 9.33 s for 300 frames, versus 10.00 s in software. This limits seeking, variable-frame-rate playback, and audio synchronization. No speculative driver patch or general timestamp repair was applied.
For the known 30-fps, silent BBB experiment only, mpv can generate timing with
--correct-pts=no --container-fps-override=30. That is a scoped workaround,
not acceptance of MVX timestamps for arbitrary media.
Streaming and window size
The original public remote MPD is
https://dash.akamaized.net/akamai/bbb_30fps/bbb_30fps.mpd.
All following runs request the same 30 seconds, starting at 45 seconds, with
--cache=yes --demuxer-readahead-secs=30 --vo=wlshm --profile=sw-fast.
A Sway rule makes the k230-video-probe window floating and borderless at the
specified size. --geometry alone does not constrain a tiled Sway window.
| Trial | Source / output | Decoder | Decoder / VO drops |
|---|---|---|---|
| Software, video-sized window | 480×270 / 480×270 | native H.264 | 0 / 0 |
| MVX, fixed 30-fps timing | 640×360 / 568×320 | MVX | 0 / 134 |
| Same, internal vsync disabled | 640×360 / 568×320 | MVX | 0 / 138 |
| MVX, point scaling, internal vsync auto | 640×360 / 568×320 | MVX | 0 / 0 |
The 270p result improves on the earlier 106-drop tiled-window observation. Window size and explicit cache settings changed together, so this is a usable configuration comparison, not an isolated attribution of all improvement to one flag. Network buffers stayed ahead in the original-URL trials.
An intermediate experiment used a filtered MPD stored locally. Both native and MVX runs kept only about one second of cache and advanced in bursts. Their zero-drop counters are excluded from acceptance; they do not establish smooth playback. A first seek/duration-limited FFmpeg DASH trial was also discarded as a throughput benchmark in favor of the fixed-frame local comparison above.
The software baseline uses an unscaled YUV-to-BGRA converter. The 360p output still uses CPU scaling (bilinear in the first trials, point in the successful configuration); neither the VPU nor the KPU accelerates this Wayland SHM rendering path. Counters describe player behavior, not a measured panel scanout cadence. Physical/native captures and a presentation-timing acceptance remain separate evidence layers in the video proposal.
The decisive 360p setting was --sws-scaler=point, placed after
--profile=sw-fast so that the profile does not overwrite it with bilinear.
The first attempt put it before the profile and still logged bilinear; that
attempt is not a point-scaler result. The corrected log explicitly records
nearest-neighbor/point scaling. This trades interpolation quality for speed.
tools/play-bbb-probe.sh preserves two bounded recipes: software for
unscaled 270p with native timing, and mvx for 360p with point scaling and the
known-CFR timing override. Run it as the shell user with the built mpv path and
its Wayland/Sway environment. It runs the public 30-second test, with audio off.
Compositor versus 2.5D GPU
Sway currently forces the CPU Pixman renderer. That is not evidence that the
chip lacks graphics acceleration: the live GPU preflight
records CONFIG_GPU_VGLITE=y and a root-only /dev/vg_lite device. DRM exposes
card0 but no render node. The VG-Lite 2.5D engine is a different integration
path from a Mesa/OpenGL renderer; it is not used by the current shell or these
wlshm playback tests. The separate offscreen RGBX blit/scale test passed; the
GPU integration audit records the initial RGBA
color mismatch and the remaining display-buffer work. This is separate from
the proven VPU decode result above.
Captured repeat
The same 360p/point/CFR configuration was repeated while taking a compositor screenshot and a host-camera recording. This captured run reported 0 decoder and 2 video-output drops, versus 0/0 in the earlier run. The screenshot adds work on the board; this record does not isolate whether that caused the two drops. Both outcomes are retained.
Native screenshot, four-second physical clip and camera still show the actual decoded movie. The camera crop excludes the surrounding body/desk scene; provenance records its coordinates, timing, source hash and autofocus setting. It is an oblique hand-held camera view, not a panel frame-rate measurement. The source recording remains private on the host; only selected derivatives are published.
The captured repeat stopped advancing at the requested final frame but did not finish process teardown promptly. The coordinator terminated that identified mpv process; cleanup confirms no player remains and shell, seatd, and Wi-Fi stay active. The diagnostic wrapper therefore has a 90-second wall clock limit with a three-second termination grace period. This is a guard for the bounded probe, not a claim that integrated EOF/error recovery is solved. The earlier point-scaler run did return EOF normally.