From bb22847d1134723d6ed67ef0aaeb44c6af53e3da Mon Sep 17 00:00:00 2001 From: Ming Qian Date: Wed, 17 Dec 2025 11:02:23 +0800 Subject: [PATCH] media: amphion: Trigger source change if colorspace changed After encountering a colorspace change in the stream, the decoder sends a V4L2_EVENT_SOURCE_CHANGE event with changes set to V4L2_EVENT_SRC_CH_RESOLUTION. Then the client can detect and handle the colorspace change without any buffer reallocation Signed-off-by: Ming Qian Reviewed-by: Nicolas Dufresne Signed-off-by: Nicolas Dufresne Signed-off-by: Hans Verkuil --- drivers/media/platform/amphion/vdec.c | 61 +++++++++++++++-------- drivers/media/platform/amphion/vpu_v4l2.c | 1 - 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index f25dbcebdccf6..beeaf75c76b44 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -950,7 +950,7 @@ static void vdec_stop_done(struct vpu_inst *inst) vpu_inst_unlock(inst); } -static bool vdec_check_source_change(struct vpu_inst *inst) +static bool vdec_check_source_change(struct vpu_inst *inst, struct vpu_dec_codec_info *hdr) { struct vdec_t *vdec = inst->priv; const struct vpu_format *sibling; @@ -962,26 +962,35 @@ static bool vdec_check_source_change(struct vpu_inst *inst) return false; sibling = vpu_helper_find_sibling(inst, inst->cap_format.type, inst->cap_format.pixfmt); - if (sibling && vdec->codec_info.pixfmt == sibling->pixfmt) - vdec->codec_info.pixfmt = inst->cap_format.pixfmt; + if (sibling && hdr->pixfmt == sibling->pixfmt) + hdr->pixfmt = inst->cap_format.pixfmt; if (!vb2_is_streaming(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx))) return true; - if (inst->cap_format.pixfmt != vdec->codec_info.pixfmt) + if (inst->cap_format.pixfmt != hdr->pixfmt) return true; - if (inst->cap_format.width != vdec->codec_info.decoded_width) + if (inst->cap_format.width != hdr->decoded_width) return true; - if (inst->cap_format.height != vdec->codec_info.decoded_height) + if (inst->cap_format.height != hdr->decoded_height) return true; if (vpu_get_num_buffers(inst, inst->cap_format.type) < inst->min_buffer_cap) return true; - if (inst->crop.left != vdec->codec_info.offset_x) + if (inst->crop.left != hdr->offset_x) return true; - if (inst->crop.top != vdec->codec_info.offset_y) + if (inst->crop.top != hdr->offset_y) return true; - if (inst->crop.width != vdec->codec_info.width) + if (inst->crop.width != hdr->width) return true; - if (inst->crop.height != vdec->codec_info.height) + if (inst->crop.height != hdr->height) + return true; + if (!hdr->progressive) + return true; + + if (vdec->seq_hdr_found && + (hdr->color_primaries != vdec->codec_info.color_primaries || + hdr->transfer_chars != vdec->codec_info.transfer_chars || + hdr->matrix_coeffs != vdec->codec_info.matrix_coeffs || + hdr->full_range != vdec->codec_info.full_range)) return true; return false; @@ -1333,20 +1342,25 @@ static void vdec_event_seq_hdr(struct vpu_inst *inst, struct vpu_dec_codec_info struct vdec_t *vdec = inst->priv; vpu_inst_lock(inst); - memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info)); - vpu_trace(inst->dev, "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d\n", + vpu_trace(inst->dev, + "[%d] %d x %d, crop : (%d, %d) %d x %d, %d, %d, colorspace: %d, %d, %d, %d\n", inst->id, - vdec->codec_info.decoded_width, - vdec->codec_info.decoded_height, - vdec->codec_info.offset_x, - vdec->codec_info.offset_y, - vdec->codec_info.width, - vdec->codec_info.height, + hdr->decoded_width, + hdr->decoded_height, + hdr->offset_x, + hdr->offset_y, + hdr->width, + hdr->height, hdr->num_ref_frms, - hdr->num_dpb_frms); + hdr->num_dpb_frms, + hdr->color_primaries, + hdr->transfer_chars, + hdr->matrix_coeffs, + hdr->full_range); inst->min_buffer_cap = hdr->num_ref_frms + hdr->num_dpb_frms; - vdec->is_source_changed = vdec_check_source_change(inst); + vdec->is_source_changed = vdec_check_source_change(inst, hdr); + memcpy(&vdec->codec_info, hdr, sizeof(vdec->codec_info)); vdec_init_fmt(inst); vdec_init_crop(inst); vdec_init_mbi(inst); @@ -1375,7 +1389,12 @@ static void vdec_event_resolution_change(struct vpu_inst *inst) { struct vdec_t *vdec = inst->priv; - vpu_trace(inst->dev, "[%d]\n", inst->id); + vpu_trace(inst->dev, "[%d] input : %d, decoded : %d, display : %d, sequence : %d\n", + inst->id, + vdec->params.frame_count, + vdec->decoded_frame_count, + vdec->display_frame_count, + vdec->sequence); vpu_inst_lock(inst); vdec->seq_tag = vdec->codec_info.tag; vdec_clear_fs(&vdec->mbi); diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 47dff9a35bb46..121165a7184fc 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -102,7 +102,6 @@ static int vpu_notify_eos(struct vpu_inst *inst) int vpu_notify_source_change(struct vpu_inst *inst) { static const struct v4l2_event ev = { - .id = 0, .type = V4L2_EVENT_SOURCE_CHANGE, .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; -- 2.47.3