From 86a8545146ed26c2ff3ecb481b025e5635dc0dad Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Fri, 1 May 2026 12:00:00 +0000 Subject: [PATCH] h264: fill DECODE_PARAMS frame_num + field flags from VAAPI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fourier's h264_va_picture_to_v4l2 only populated four fields of the struct v4l2_ctrl_h264_decode_params: dpb (via h264_fill_dpb), nal_ref_idc, top_field_order_cnt, bottom_field_order_cnt, and the IDR_PIC flag. Many other required-by-spec fields were left at zero- init (frame_num, idr_pic_id, pic_order_cnt_lsb, delta_pic_order_cnt_*, dec_ref_pic_marking_bit_size, pic_order_cnt_bit_size, slice_group_change_cycle, FIELD_PIC and BOTTOM_FIELD flags). For an IDR (first frame) on hantro-vpu RK3568, the kernel parses the bitstream from the OUTPUT buffer and uses these fields to drive its bitstream-element offset tracking. Empirically the kernel returned a successfully-decoded but ZEROED CAPTURE buffer — flat dark-green frames in mpv output, no errors logged. This patch fills every field VAAPI exposes: - frame_num: from VAPicture->frame_num. - FIELD_PIC flag: from VAPicture->pic_fields.bits.field_pic_flag. - BOTTOM_FIELD flag: from VAPicture->CurrPic.flags & VA_PICTURE_H264_BOTTOM_FIELD. Also corrects the IDR_PIC flag to use |= instead of = so the new field flags don't clobber it. Fields NOT derivable from VAAPI's pre-parsed structures — idr_pic_id, pic_order_cnt_lsb, delta_pic_order_cnt_*, dec_ref_pic_marking_bit_size, pic_order_cnt_bit_size, slice_group_change_cycle — require a slice_header() bit-level parse. libva-v4l2-request does not currently do this. They remain at zero-init. Empirical question this patch answers: does hantro tolerate the bit_size fields being zero for IDR frames, or does it strictly require them? If post-patch CAPTURE is still zeroed, a slice-header parser is required. If CAPTURE shows real picture data, hantro fills in the bit-positions itself when no hint is supplied. Cross-reference: gstv4l2codech264dec.c:: gst_v4l2_codec_h264_dec_fill_decoder_params (commit 9e3e775, lines 632-678). Signed-off-by: Markus Fritsche --- src/h264.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/h264.c b/src/h264.c index 0ae5724..b5c712d 100644 --- a/src/h264.c +++ b/src/h264.c @@ -243,13 +243,34 @@ static void h264_va_picture_to_v4l2(struct request_data *driver_data, h264_fill_dpb(driver_data, context, decode); - //decode->num_slices = surface->slices_count; + /* + * Populate every V4L2_CID_STATELESS_H264_DECODE_PARAMS field + * we can derive from VAAPI's pre-parsed VAPictureParameterBuffer + * + bitstream byte. Cross-reference: GStreamer + * gstv4l2codech264dec.c::gst_v4l2_codec_h264_dec_fill_decoder_params + * (lines 632-678). + * + * Fields not derivable from VAAPI (idr_pic_id, pic_order_cnt_lsb, + * delta_pic_order_cnt_*, dec_ref_pic_marking_bit_size, + * pic_order_cnt_bit_size, slice_group_change_cycle) require a + * full slice_header() bit-level parse, which libva-v4l2-request + * does not currently do. They are left at zero-init and the + * kernel-side hantro-vpu may compute them itself when scanning + * the OUTPUT bitstream — a hypothesis verified empirically by + * running this patch and inspecting the CAPTURE buffer. + */ decode->nal_ref_idc = nal_ref_idc; - if (nal_unit_type == 5) - decode->flags = V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC; + decode->frame_num = VAPicture->frame_num; decode->top_field_order_cnt = VAPicture->CurrPic.TopFieldOrderCnt; decode->bottom_field_order_cnt = VAPicture->CurrPic.BottomFieldOrderCnt; + if (nal_unit_type == 5) + decode->flags |= V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC; + if (VAPicture->pic_fields.bits.field_pic_flag) + decode->flags |= V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC; + if (VAPicture->CurrPic.flags & VA_PICTURE_H264_BOTTOM_FIELD) + decode->flags |= V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD; + pps->weighted_bipred_idc = VAPicture->pic_fields.bits.weighted_bipred_idc; pps->pic_init_qs_minus26 = VAPicture->pic_init_qs_minus26;