diff --git a/src/context.c b/src/context.c index 9f2ffd0..c05caf2 100644 --- a/src/context.c +++ b/src/context.c @@ -195,6 +195,94 @@ VAStatus RequestCreateContext(VADriverContextP context, VAConfigID config_id, goto error; } + /* + * iter25 α-25: synthetic-SPS injection to pre-seed ctx->image_fmt + * before CAPTURE buffer allocation. + * + * Root cause (iter17→iter24 kernel-printk chain): rkvdec_s_ctrl for + * HEVC_SPS / H264_SPS calls get_image_fmt() and, if the resolved + * image_fmt differs from the cached ctx->image_fmt (default + * RKVDEC_IMG_FMT_ANY), tries to reset the CAPTURE format. The reset + * returns -EBUSY when vb2_is_busy(CAPTURE_queue) — i.e. any CAPTURE + * buffer is allocated. + * + * libva (iter5b-β CAPTURE pool) pre-allocates 24 CAPTURE buffers + * via cap_pool_init below — before any per-frame S_EXT_CTRLS + * arrives. So the first real HEVC_SPS at decode time fails with + * -EBUSY in try_or_set_cluster, breaks v4l2_ctrl_request_setup's + * outer loop, and leaves ctx->ctrl_hdl[SPS..DECODE_PARAMS] at all- + * zero contents. rkvdec_hevc_run reads zero, hardware sees w=0 + * h=0, decoded CAPTURE is all-zero (Bug 5 + Bug 4). + * + * Fix: while CAPTURE is still empty (before cap_pool_init), inject + * a synthetic SPS containing the profile's chroma + bit_depth so + * rkvdec_s_ctrl resolves image_fmt and updates ctx->image_fmt + * before vb2_is_busy can return true. From then on, per-frame + * SPS submissions with matching profile parameters see + * image_fmt_changed=false → skip reset → commit succeeds. + * + * Gated by config->profile: only HEVC and H.264 paths set + * get_image_fmt in their rkvdec coded_fmt_desc->ops; VP9 / MPEG-2 / + * VP8 are unaffected (rkvdec_s_ctrl returns 0 immediately when + * get_image_fmt is NULL, or those codecs are routed to hantro). + * + * Failure is best-effort: if the kernel returns -EBUSY/-EINVAL here + * (e.g. driver doesn't expose the control on this DT path), we fall + * through and may still hit the original bug for that codec — but + * the device-init DECODE_MODE + START_CODE block below ALSO uses + * void-cast best-effort, so this is consistent with prior pattern. + */ + { + switch (config_object->profile) { + case VAProfileHEVCMain: { + struct v4l2_ctrl_hevc_sps dummy_sps; + struct v4l2_ext_control dummy_ctrl; + + memset(&dummy_sps, 0, sizeof(dummy_sps)); + dummy_sps.chroma_format_idc = 1; /* 4:2:0 */ + dummy_sps.bit_depth_luma_minus8 = 0; /* 8-bit */ + dummy_sps.bit_depth_chroma_minus8 = 0; + dummy_sps.pic_width_in_luma_samples = picture_width; + dummy_sps.pic_height_in_luma_samples = picture_height; + + dummy_ctrl.id = V4L2_CID_STATELESS_HEVC_SPS; + dummy_ctrl.ptr = &dummy_sps; + dummy_ctrl.size = sizeof(dummy_sps); + (void)v4l2_set_controls(driver_data->video_fd, -1, + &dummy_ctrl, 1); + break; + } + case VAProfileH264Main: + case VAProfileH264High: + case VAProfileH264ConstrainedBaseline: + case VAProfileH264MultiviewHigh: + case VAProfileH264StereoHigh: { + struct v4l2_ctrl_h264_sps dummy_sps; + struct v4l2_ext_control dummy_ctrl; + + memset(&dummy_sps, 0, sizeof(dummy_sps)); + dummy_sps.chroma_format_idc = 1; /* 4:2:0 */ + dummy_sps.bit_depth_luma_minus8 = 0; + dummy_sps.bit_depth_chroma_minus8 = 0; + dummy_sps.pic_width_in_mbs_minus1 = + (picture_width + 15) / 16 - 1; + dummy_sps.pic_height_in_map_units_minus1 = + (picture_height + 15) / 16 - 1; + dummy_sps.profile_idc = 100; /* High */ + dummy_sps.level_idc = 41; + + dummy_ctrl.id = V4L2_CID_STATELESS_H264_SPS; + dummy_ctrl.ptr = &dummy_sps; + dummy_ctrl.size = sizeof(dummy_sps); + (void)v4l2_set_controls(driver_data->video_fd, -1, + &dummy_ctrl, 1); + break; + } + default: + break; + } + } + destination_planes_count = video_format->planes_count; /*