h264: hardcode SPS level_idc = 51 (intentional over-allocation)

fourier's h264_va_picture_to_v4l2 never assigns sps->level_idc; the
field stays at zero-init. level_idc=0 is invalid per the H.264 spec
(lowest legal value is 10, Level 1.0). Hantro and other stateless
H.264 decoders use level_idc to pre-allocate decoder resources (DPB
size, motion-vector buffers); when fed an invalid level the hantro
kernel driver silently skips the decode-hardware dispatch — the V4L2
request completes with no error, DQBUF returns the CAPTURE buffer
reporting bytesused=3655712 and no V4L2_BUF_FLAG_ERROR, but the
buffer is never written.

VAAPI's decode-side VAPictureParameterBufferH264 structurally does
NOT include level_idc — `grep level_idc va/va.h` returns only hits
inside VAEncSequenceParameterBufferH264 (the encode path). The
H.264 SPS NAL is also not included in VASliceDataBuffer because
ffmpeg-vaapi parses it client-side and forwards only slice data
(verified empirically via patch 0010's hex-dump of the OUTPUT
buffer: it contains "00 00 01 65 ..." — i.e. ANNEX_B start code +
IDR slice NAL byte, no SPS NAL). A SPS-NAL byte extractor is
therefore not viable from the bitstream libva-v4l2-request
receives.

Workaround: hardcode level_idc = 51 (= Level 5.1, max for 1080p
and 4K@30 mainstream consumer profiles). This INTENTIONALLY
OVER-ALLOCATES decoder resources but is sufficient for any stream
up to 4K@30. It is corpus-correct, not contract-correct: a 4K@60
stream (Level 6.x) would under-allocate.

This patch is a known-incomplete intermediate, not a final fix.
The proper upstreamable answer is a level-from-resolution
derivation per H.264 Annex A.3 (max MB rate / max frame size
thresholds). That requires mapping consumer-side framerate which
VAAPI does not expose, so the lookup table is non-trivial. The
TODO is captured inline.

This patch's goal is unblocking decode-hardware engagement on the
ohm_gl_fix corpus while the full level-derivation work proceeds.

Cross-reference: kernel doc
ext-ctrls-codec-stateless.rst V4L2_CID_STATELESS_H264_SPS lists
level_idc as a required field with no "kernel-derives" annotation —
i.e., userspace-required.

Signed-off-by: Markus Fritsche <fritsche.markus@gmail.com>
This commit is contained in:
2026-05-02 12:00:00 +00:00
parent 841f616e74
commit c672f19f44
+29
View File
@@ -552,6 +552,35 @@ int h264_set_controls(struct request_data *driver_data,
sps.profile_idc = h264_profile_to_idc(profile); sps.profile_idc = h264_profile_to_idc(profile);
/*
* VAAPI's decode-side VAPictureParameterBufferH264 does not carry
* level_idc — see va.h, the field exists only in
* VAEncSequenceParameterBufferH264 on the encode path. The H.264
* SPS NAL is also not included in VASliceDataBuffer (ffmpeg-vaapi
* parses it client-side and forwards only slice data), so a
* SPS-NAL byte extractor is not viable from the bitstream we
* receive.
*
* Hantro and other stateless H.264 decoders use level_idc to
* pre-allocate decoder resources (DPB, motion-vector buffers); a
* zero-init level_idc=0 is invalid (lowest legal is 10 = Level
* 1.0) and causes hantro to silently skip the decode hardware
* dispatch.
*
* Hardcode level_idc = 51 (Level 5.1, max for 1080p/4K@30) as a
* known-incomplete intermediate. This INTENTIONALLY OVER-ALLOCATES
* decoder resources and is sufficient for any stream up to 4K@30.
* It is corpus-correct, not contract-correct.
*
* TODO: derive level_idc from (VAProfile, picture_width_in_mbs,
* picture_height_in_mbs) per H.264 Annex A.3 max-MB-per-second
* thresholds. That is a small lookup table but requires also
* mapping the consumer's framerate, which VAAPI doesn't provide
* directly. For now the over-allocation is the upstreamable
* compromise.
*/
sps.level_idc = 51;
/* /*
* Build the per-request control list incrementally: * Build the per-request control list incrementally:
* - SPS, PPS, DECODE_PARAMS: always required (in either decode * - SPS, PPS, DECODE_PARAMS: always required (in either decode