From fc4bb1063fd57d7790417d7381dc06d961c5c30d Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Sat, 25 Apr 2026 21:51:43 +0000 Subject: [PATCH] src/h264.c: track upstream UAPI shape for H.264 controls The H.264 stateless control structs and CIDs were upstreamed and reshaped during the journey from libva-v4l2-request's bundled headers to the kernel's . Three breaking changes need matching code-side updates: 1. struct v4l2_ctrl_h264_slice_params lost its .size field. The full slice byte length is now communicated via the OUTPUT buffer's m.planes[0].bytesused at QBUF time, which v4l2_queue_buffer already sets. Drop the assignment. 2. struct v4l2_h264_reference replaces the bare integer DPB index in ref_pic_list0[] / ref_pic_list1[]. The new struct is { __u8 fields, __u8 index } where `fields` is V4L2_H264_TOP_FIELD_REF (0x1) / BOTTOM_FIELD_REF (0x2) / FRAME_REF (0x3). Hantro G1 only does frame-based H.264, so use V4L2_H264_FRAME_REF unconditionally. 3. The pred_weight_table block moved out of slice_params into its own V4L2_CID_STATELESS_H264_PRED_WEIGHTS control with struct v4l2_ctrl_h264_pred_weights. Add it as a separate v4l2_set_control() call alongside SPS/PPS/SLICE_PARAMS/DECODE_PARAMS/SCALING_MATRIX, and thread the pred_weights pointer through h264_va_slice_to_v4l2(). Also: switch the v4l2_set_control() CID arguments from V4L2_CID_MPEG_VIDEO_H264_* to V4L2_CID_STATELESS_H264_* directly. h264-ctrls.h still defines the old names as aliases so external callers keep working, but using the canonical names internally matches what the kernel actually expects and avoids confusion when reading h264.c side-by-side with the kernel source. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/h264.c | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/h264.c b/src/h264.c index 5599231..03cd634 100644 --- a/src/h264.c +++ b/src/h264.c @@ -328,9 +328,12 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, struct object_context *context, VASliceParameterBufferH264 *VASlice, VAPictureParameterBufferH264 *VAPicture, - struct v4l2_ctrl_h264_slice_params *slice) + struct v4l2_ctrl_h264_slice_params *slice, + struct v4l2_ctrl_h264_pred_weights *pred_weights) { - slice->size = VASlice->slice_data_size; + /* Slice byte size is now communicated via the OUTPUT buffer's + * bytesused at QBUF time; the v4l2_ctrl_h264_slice_params struct + * was slimmed during upstreaming and no longer carries it. */ slice->header_bit_size = VASlice->slice_data_bit_offset; slice->first_mb_in_slice = VASlice->first_mb_in_slice; slice->slice_type = VASlice->slice_type; @@ -357,7 +360,8 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, if (!entry) continue; - slice->ref_pic_list0[i] = idx; + slice->ref_pic_list0[i].index = idx; + slice->ref_pic_list0[i].fields = V4L2_H264_FRAME_REF; } } @@ -376,21 +380,24 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, if (!entry) continue; - slice->ref_pic_list1[i] = idx; + slice->ref_pic_list1[i].index = idx; + slice->ref_pic_list1[i].fields = V4L2_H264_FRAME_REF; } } if (VASlice->direct_spatial_mv_pred_flag) slice->flags |= V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED; - slice->pred_weight_table.chroma_log2_weight_denom = + /* Predicted weight table moved out of slice_params into its own + * V4L2_CID_STATELESS_H264_PRED_WEIGHTS control during upstreaming. */ + pred_weights->chroma_log2_weight_denom = VASlice->chroma_log2_weight_denom; - slice->pred_weight_table.luma_log2_weight_denom = + pred_weights->luma_log2_weight_denom = VASlice->luma_log2_weight_denom; if (((VASlice->slice_type % 5) == H264_SLICE_P) || ((VASlice->slice_type % 5) == H264_SLICE_B)) - h264_copy_pred_table(&slice->pred_weight_table.weight_factors[0], + h264_copy_pred_table(&pred_weights->weight_factors[0], slice->num_ref_idx_l0_active_minus1 + 1, VASlice->luma_weight_l0, VASlice->luma_offset_l0, @@ -398,7 +405,7 @@ static void h264_va_slice_to_v4l2(struct request_data *driver_data, VASlice->chroma_offset_l0); if ((VASlice->slice_type % 5) == H264_SLICE_B) - h264_copy_pred_table(&slice->pred_weight_table.weight_factors[1], + h264_copy_pred_table(&pred_weights->weight_factors[1], slice->num_ref_idx_l1_active_minus1 + 1, VASlice->luma_weight_l1, VASlice->luma_offset_l1, @@ -413,6 +420,7 @@ int h264_set_controls(struct request_data *driver_data, struct v4l2_ctrl_h264_scaling_matrix matrix = { 0 }; struct v4l2_ctrl_h264_decode_params decode = { 0 }; struct v4l2_ctrl_h264_slice_params slice = { 0 }; + struct v4l2_ctrl_h264_pred_weights pred_weights = { 0 }; struct v4l2_ctrl_h264_pps pps = { 0 }; struct v4l2_ctrl_h264_sps sps = { 0 }; struct h264_dpb_entry *output; @@ -434,32 +442,39 @@ int h264_set_controls(struct request_data *driver_data, &surface->params.h264.matrix, &matrix); h264_va_slice_to_v4l2(driver_data, context, &surface->params.h264.slice, - &surface->params.h264.picture, &slice); + &surface->params.h264.picture, &slice, + &pred_weights); rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS, &decode, + V4L2_CID_STATELESS_H264_DECODE_PARAMS, &decode, sizeof(decode)); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS, &slice, + V4L2_CID_STATELESS_H264_SLICE_PARAMS, &slice, sizeof(slice)); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_PPS, &pps, sizeof(pps)); + V4L2_CID_STATELESS_H264_PRED_WEIGHTS, + &pred_weights, sizeof(pred_weights)); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SPS, &sps, sizeof(sps)); + V4L2_CID_STATELESS_H264_PPS, &pps, sizeof(pps)); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED; rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, - V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX, &matrix, + V4L2_CID_STATELESS_H264_SPS, &sps, sizeof(sps)); + if (rc < 0) + return VA_STATUS_ERROR_OPERATION_FAILED; + + rc = v4l2_set_control(driver_data->video_fd, surface->request_fd, + V4L2_CID_STATELESS_H264_SCALING_MATRIX, &matrix, sizeof(matrix)); if (rc < 0) return VA_STATUS_ERROR_OPERATION_FAILED;