Files
fresnel-fourier/phase8_iteration38_close.md
T
marfrit ba4b6fd240 iter38 close: multi-device probe — 5/5 codecs in one libva session
Closes the last architectural open item from iter37 campaign-close.

VA_DRIVER_INIT now opens BOTH rkvdec and hantro fds when no env
override is set. RequestQueryConfigProfiles enumerates the union
(via any_fd_supports_output_format helper). RequestCreateConfig
calls request_switch_device_for_profile to retarget the active fd
to the device that serves the profile; tears down output_pool +
capture_pool + video_format cache on switch so the next
RequestCreateContext rebuilds them on the new device.

Bonus iter38b: fixed latent bounds-check bug in
RequestQueryConfigProfiles — profile array bounds checks should use
MAX_PROFILES (11), not MAX_CONFIG_ATTRIBUTES (10). Pre-iter38 single-
device probes never returned more than 9 profiles so the off-by-one
never bit. iter38's 10-profile union surfaced it.

Result: 5/5 codecs PASS bit-exact vs kdirect with NO env override.

  $ vainfo (no env)
  v4l2-request: auto-selected: /dev/video3 + /dev/media1
  v4l2-request: iter38: also opened hantro at /dev/video2 + /dev/media0
  → all 10 profiles enumerated (MPEG2+H264+HEVC+VP8+VP9)

Backend tip 7ac934e.
2026-05-14 18:58:17 +00:00

4.9 KiB

Iteration 38 — Phase 8 (close): Multi-device probe — 5/5 codecs in a single libva session

Closes 2026-05-14, eighth campaign-day milestone. The last remaining "architectural" open item from iter37.

Goal

Before iter38, libva backend's find_codec_device (single-device auto-probe) tied a session to ONE physical decoder. Users had to set LIBVA_V4L2_REQUEST_VIDEO_PATH=/dev/video3 LIBVA_V4L2_REQUEST_MEDIA_PATH=/dev/media1 to use rkvdec (H264/HEVC/VP9) or …video2 …media0 to use hantro (VP8/MPEG-2). A single ffmpeg invocation could never serve all 5 codecs.

iter38 makes the auto-probe path open BOTH devices and retarget on-the-fly per-config so a single libva session supports the full 5-codec set.

Design

struct request_data gains four fields (in addition to the existing active video_fd / media_fd):

int video_fd_rkvdec;
int media_fd_rkvdec;
int video_fd_hantro;
int media_fd_hantro;

VA_DRIVER_INIT flow:

  1. Auto-detect the primary decoder (current behaviour: prefer rkvdec, fall back to hantro). Open its video_fd + media_fd.
  2. Identify the primary by MEDIA_IOC_DEVICE_INFO::driver name → tag the appropriate primary *_fd_rkvdec or *_fd_hantro pair.
  3. Probe the OTHER known decoder via find_decoder_device_by_driver(). Open its fds into the unused pair. -1 if not present.
  4. Skip the alt-probe when LIBVA_V4L2_REQUEST_VIDEO_PATH or LIBVA_V4L2_REQUEST_MEDIA_PATH is set (explicit single-device intent).

RequestQueryConfigProfiles now iterates the active fd and the two alt fds via a helper any_fd_supports_output_format(), returning the UNION of supported profiles.

RequestCreateConfig calls a new helper request_switch_device_for_profile(driver_data, profile):

  • Maps profile → device kind ('r' for rkvdec / 'h' for hantro).
  • If the active fd is wrong, tear down output_pool, capture_pool, and video_format cache, then retarget driver_data->{video,media}_fd to the target pair.
  • If the required device kind wasn't probed, no-op (caller's LIBVA_V4L2_REQUEST_VIDEO_PATH override took precedence).

RequestTerminate closes BOTH fd pairs.

Bonus fix: iter38b bounds correction

While testing iter38, VP9 disappeared from the auto-detect profile list — surfaced a LATENT off-by-one in RequestQueryConfigProfiles. The profiles[] buffer is sized by V4L2_REQUEST_MAX_PROFILES (11), but the bounds checks used V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES (10). Pre-iter38 single-device probe never returned more than 9 profiles, so the off-by-one never bit. iter38's 10-profile union pushed VP9 (the 10th profile) past the check. Fixed all bounds to use MAX_PROFILES.

Result

$ vainfo (NO env override)
v4l2-request: auto-selected codec device: /dev/video3 + /dev/media1
v4l2-request: iter38: also opened hantro-vpu decoder at /dev/video2 + /dev/media0
vainfo: Driver version: v4l2-request
vainfo: Supported profile and entrypoints
      VAProfileMPEG2Simple            : VAEntrypointVLD
      VAProfileMPEG2Main              : VAEntrypointVLD
      VAProfileH264Main               : VAEntrypointVLD
      VAProfileH264High               : VAEntrypointVLD
      VAProfileH264ConstrainedBaseline: VAEntrypointVLD
      VAProfileH264MultiviewHigh      : VAEntrypointVLD
      VAProfileH264StereoHigh         : VAEntrypointVLD
      VAProfileHEVCMain               : VAEntrypointVLD
      VAProfileVP8Version0_3          : VAEntrypointVLD
      VAProfileVP9Profile0            : VAEntrypointVLD

5-codec regression (NO env override, each ffmpeg invocation fresh process):

Codec libva sha-16 kdirect sha-16 Match
H.264 dd4f5f2d552c07bc same
HEVC 108f925bb6cbb6c9 same
VP9 cf35908ae0f9ab60 same
VP8 d3231e5b6c0ee10b same
MPEG-2 95c5905890c937d4 same

5/5 PASS in a single libva session without LIBVA_V4L2_REQUEST_VIDEO_PATH per codec.

Substrate state at iter38 close

  • Backend fork tip 7ac934e (iter38 + iter38b)
  • Kernel linux-fresnel-fourier 7.0-14 (clean, unchanged from iter34)
  • Removed env knobs: VP8/MPEG-2 no longer need explicit device routing
  • Retained env knobs: LIBVA_V4L2_REQUEST_VIDEO_PATH / MEDIA_PATH still work for forced single-device testing

Open items remaining (post iter38)

The campaign is now at its definitive close. No urgent open items.

Optional follow-ups:

  • Multi-context simultaneously: current design allows only one decode context at a time across devices (a device switch tears down pools). Could be expanded to per-context pools to support simultaneous mixed-codec decode. Not requested.
  • Sub-profile support (H264 Hi10, HEVC Main10, VP9 Profile 2): rkvdec supports these on RK3399 but the libva backend has no entries for them in pixelformat_for_profile / etc. Out of scope for this campaign.

Memory entry

feedback_multi_device_probe_design.md — design notes for the rkvdec+hantro dual-fd model, RequestQueryConfigProfiles union, and the MAX_PROFILES bounds-check gotcha.