diff --git a/src/h265.c b/src/h265.c index 6737c58..ba764ee 100644 --- a/src/h265.c +++ b/src/h265.c @@ -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,