iter11 Phase 6 α-13 + α-14: HEVC SPS hygiene + IRAP/IDR flags fix Bug 5

Two fixes in one commit:

α-13 (h265_fill_sps): sps_max_num_reorder_pics now derived from
sps_max_dec_pic_buffering_minus1 (safe upper bound per H.265 §A.4.2)
instead of hardcoded 0. Phase 5b empirically showed rkvdec ignores
this field on RK3399, so this is wire-correctness hygiene only — matches
kdirect's payload pattern without behavior change.

α-14 (h265_set_controls): derive IRAP_PIC / IDR_PIC flags from the
first slice's nal_unit_type (parsed by h265_fill_slice_params into
slice_params_array[0].nal_unit_type). Without these flags rkvdec
doesn't recognise the keyframe boundary, treats IDR as inter without
references, and produces all-zero CAPTURE output — observed as Bug 5
on libva HEVC (06b2c5a0...). kdirect sets these from the bitstream
parse and decodes correctly (9340b832...).

Mapping:
  nal_unit_type 16..23 -> IRAP_PIC
  nal_unit_type 19 (IDR_W_RADL) or 20 (IDR_N_LP) -> IDR_PIC

HEVC-only (no risk to other codecs). h265_set_controls already
profile-gated via picture.c::codec_set_controls VAProfileHEVCMain
dispatch. Per feedback_unconditional_codec_state.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude-noether
2026-05-14 06:01:22 +00:00
parent e0be4e6992
commit 8e2c04f84b
+53 -5
View File
@@ -107,8 +107,20 @@ static void h265_fill_sps(VAPictureParameterBufferHEVC *picture,
picture->log2_max_pic_order_cnt_lsb_minus4;
sps->sps_max_dec_pic_buffering_minus1 =
picture->sps_max_dec_pic_buffering_minus1;
sps->sps_max_num_reorder_pics = 0; /* not exposed */
sps->sps_max_latency_increase_plus1 = 0; /* not exposed */
/*
* iter11 α-13: VAAPI doesn't forward sps_max_num_reorder_pics or
* sps_max_latency_increase_plus1. kdirect parses the SPS NAL and
* submits the bitstream's true values; libva used to hardcode 0
* (a structurally wrong "no reordering" hint, even though Phase 5b
* empirically confirmed rkvdec ignores both fields on RK3399, so
* this is wire-hygiene only — matches kdirect's payload more
* closely without behavior change). sps_max_dec_pic_buffering_minus1
* is a safe upper bound per H.265 §A.4.2 (sps_max_num_reorder_pics ≤
* sps_max_dec_pic_buffering_minus1 always holds). latency_increase_plus1
* stays at 0 = spec "unconstrained".
*/
sps->sps_max_num_reorder_pics = picture->sps_max_dec_pic_buffering_minus1;
sps->sps_max_latency_increase_plus1 = 0;
sps->log2_min_luma_coding_block_size_minus3 =
picture->log2_min_luma_coding_block_size_minus3;
sps->log2_diff_max_min_luma_coding_block_size =
@@ -304,9 +316,20 @@ static void h265_fill_decode_params(struct request_data *driver_data,
* num_delta_pocs_of_ref_rps_idx left zero (VAAPI doesn't expose;
* matches FFmpeg's behavior for non-bitstream-driven population). */
/* IRAP/IDR/NO_OUTPUT_OF_PRIOR flags — VAAPI doesn't expose; computing
* from CurrPic flags + nal_unit_type would require parsing. Leave
* zero for iter2 binding cell (BBB B/P-frames don't need these set). */
/*
* iter11 α-14: IRAP/IDR/NO_OUTPUT_OF_PRIOR flags. VAAPI doesn't
* expose these in VAPictureParameterBufferHEVC. The iter2 binding
* cell hardcoded them to 0 with the comment "BBB B/P-frames don't
* need these set" — but IDR keyframes DO need IDR_PIC|IRAP_PIC.
* Without them rkvdec doesn't recognise the keyframe boundary,
* treats the IDR as inter without references, and produces all-zero
* CAPTURE output (Bug 5).
*
* The flags are derived at h265_set_controls level after slice_params
* have been parsed (slice_params[0].nal_unit_type carries the NAL
* type extracted from the bitstream). Initialise to 0 here; the caller
* patches the IRAP/IDR bits.
*/
decode_params->flags = 0;
}
@@ -549,6 +572,31 @@ int h265_set_controls(struct request_data *driver_data,
h265_fill_decode_params(driver_data, picture, &decode_params);
h265_fill_scaling_matrix(iqmatrix, iqmatrix_set, &scaling_matrix);
/*
* iter11 α-14: derive IRAP_PIC / IDR_PIC flags from the first
* slice's nal_unit_type (already parsed by h265_fill_slice_params
* from the bitstream into slice_params_array[0].nal_unit_type).
*
* H.265 §7.4.2.2:
* nal_unit_type 16..23 are IRAP (random access).
* nal_unit_type 19 (IDR_W_RADL) and 20 (IDR_N_LP) are IDR.
*
* Without setting these, rkvdec doesn't recognise the keyframe
* boundary, treats the IDR as inter without references, and
* produces all-zero CAPTURE output. Phase 3 confirmed kdirect
* (ffmpeg-v4l2request) sets flags=0x03 (IRAP|IDR) on frame 1
* and decodes correctly through the same kernel.
*/
if (num_slices > 0) {
uint8_t nut = slice_params_array[0].nal_unit_type;
if (nut >= 16 && nut <= 23)
decode_params.flags |=
V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC;
if (nut == 19 || nut == 20)
decode_params.flags |=
V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC;
}
controls[n++] = (struct v4l2_ext_control){
.id = V4L2_CID_STATELESS_HEVC_SPS,
.ptr = &sps,