From: Ming Qian <ming.qian@xxxxxxx> 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_COLORSPACE. Then the client can handle the colorspace change without any buffer reallocation Signed-off-by: Ming Qian <ming.qian@xxxxxxx> --- drivers/media/platform/amphion/vdec.c | 89 +++++++++++++++-------- drivers/media/platform/amphion/vpu.h | 1 + drivers/media/platform/amphion/vpu_v4l2.c | 7 +- 3 files changed, 63 insertions(+), 34 deletions(-) diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 3b848ac2cd0c..868a96d29fac 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -369,12 +369,16 @@ static void vdec_handle_resolution_change(struct vpu_inst *inst) if (!vdec->source_change) return; + if (inst->changes) { + vpu_notify_source_change(inst); + inst->changes = 0; + } + q = v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx); if (!list_empty(&q->done_list)) return; vdec->source_change--; - vpu_notify_source_change(inst); vpu_set_last_buffer_dequeued(inst, false); } @@ -954,10 +958,11 @@ 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; + u32 changes = 0; if (!inst->fh.m2m_ctx) return false; @@ -966,27 +971,41 @@ 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) - return true; - if (inst->cap_format.width != vdec->codec_info.decoded_width) - return true; - if (inst->cap_format.height != vdec->codec_info.decoded_height) - return true; + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->cap_format.pixfmt != hdr->pixfmt) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->cap_format.width != hdr->decoded_width) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->cap_format.height != hdr->decoded_height) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; if (vpu_get_num_buffers(inst, inst->cap_format.type) < inst->min_buffer_cap) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->crop.left != hdr->offset_x) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->crop.top != hdr->offset_y) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->crop.width != hdr->width) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (inst->crop.height != hdr->height) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + if (!hdr->progressive) + changes |= V4L2_EVENT_SRC_CH_RESOLUTION; + + 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)) + changes |= V4L2_EVENT_SRC_CH_COLORSPACE; + + if (changes) { + inst->changes |= changes; return true; - if (inst->crop.left != vdec->codec_info.offset_x) - return true; - if (inst->crop.top != vdec->codec_info.offset_y) - return true; - if (inst->crop.width != vdec->codec_info.width) - return true; - if (inst->crop.height != vdec->codec_info.height) - return true; + } return false; } @@ -1337,20 +1356,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); @@ -1379,7 +1403,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.h b/drivers/media/platform/amphion/vpu.h index 76bfd6b26170..d8100da160d1 100644 --- a/drivers/media/platform/amphion/vpu.h +++ b/drivers/media/platform/amphion/vpu.h @@ -272,6 +272,7 @@ struct vpu_inst { u8 xfer_func; u32 sequence; u32 extra_size; + u32 changes; u32 flows[16]; u32 flow_idx; diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c index 74668fa362e2..37ef706c29dd 100644 --- a/drivers/media/platform/amphion/vpu_v4l2.c +++ b/drivers/media/platform/amphion/vpu_v4l2.c @@ -96,13 +96,12 @@ 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, + const struct v4l2_event ev = { .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION + .u.src_change.changes = inst->changes }; - vpu_trace(inst->dev, "[%d]\n", inst->id); + vpu_trace(inst->dev, "[%d] source change 0x%x\n", inst->id, inst->changes); v4l2_event_queue_fh(&inst->fh, &ev); return 0; } -- 2.43.0-rc1