From 68d907ac8327305a50f238a91cef02190af862f0 Mon Sep 17 00:00:00 2001 From: Zhou Peng Date: Fri, 26 Mar 2021 20:12:16 +0800 Subject: [PATCH] arm64: imx8mx: vpu: integrate vsi 20210326 release MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit - M865SW-716: VSI V4L2 Engineer release package 20210326 M865SW-523: [VPU/V4L2] decoder: correctly handle stream file that contained codec data only M865SW-697: [VPU/V4L2] encoder: the bitrate of encoding vp8 is not accurate M865SW-707: [VPU/V4L2] daemon segmentation fault when running multi-instances M865SW-708: [VPU/V4L2] decoder: pipeline stall when playback MPEG4 stream with trick mode M865SW-710: [VPU/V4L2] daemon: wrong usage of sem_timedwait() in daemon M865SW-419: [VPU/V4L2] Pass stress test for resolution change stream M865SW-631: [VPU/V4L2] 8MM HEVC decoder: driver stall at streamoff when seek M865SW-644: [VPU/V4L2] decoder: can't recover to capture on state if stop cmd comes earlier than capture on cmd M865SW-658: [VPU/V4L2] encoder: support resolution change stream transcoding M865SW-694: [VPU/V4L2] MJPEG decoder: Android cannot playback YUV422 MJPEG streams M865SW-696: [VPU/V4L2] VC8000E: Flush encoder then get V4L2_EVENT_CODEC_ERROR event Signed-off-by: Zhou Peng (cherry picked from commit 3486e4074e606180f1b4a4c4639d58109d7a53ca) --- drivers/mxc/hantro_v4l2/vsi-v4l2-config.c | 23 ++- drivers/mxc/hantro_v4l2/vsi-v4l2-dec.c | 187 +++++++++++++++------- drivers/mxc/hantro_v4l2/vsi-v4l2-enc.c | 159 +++++++----------- drivers/mxc/hantro_v4l2/vsi-v4l2-priv.h | 23 +-- drivers/mxc/hantro_v4l2/vsi-v4l2.c | 62 +++++-- drivers/mxc/hantro_v4l2/vsi-v4l2.h | 2 + drivers/mxc/hantro_v4l2/vsi-v4l2daemon.c | 20 ++- include/uapi/linux/imx_vpu.h | 4 +- 8 files changed, 272 insertions(+), 208 deletions(-) diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2-config.c b/drivers/mxc/hantro_v4l2/vsi-v4l2-config.c index 5a5a6d37e0f3..8304132d14fa 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2-config.c +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2-config.c @@ -321,8 +321,7 @@ static struct vsi_video_fmt vsi_raw_fmt[] = { .flag = 0, }, { - .name = "YV 400", - .fourcc = V4L2_PIX_FMT_400, + .fourcc = V4L2_PIX_FMT_GREY, .enc_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE, .dec_fmt = VSI_V4L2_DEC_PIX_FMT_400, .flag = 0, @@ -335,15 +334,13 @@ static struct vsi_video_fmt vsi_raw_fmt[] = { .flag = 0, }, { - .name = "422 semi planar", - .fourcc = V4L2_PIX_FMT_422SP, + .fourcc = V4L2_PIX_FMT_NV16, .enc_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE, .dec_fmt = VSI_V4L2_DEC_PIX_FMT_422SP, .flag = 0, }, { - .name = "444 semi planar", - .fourcc = V4L2_PIX_FMT_444SP, + .fourcc = V4L2_PIX_FMT_NV24, .enc_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE, .dec_fmt = VSI_V4L2_DEC_PIX_FMT_444SP, .flag = 0, @@ -768,10 +765,10 @@ struct vsi_video_fmt *vsi_enum_dec_format(int idx, int braw, struct vsi_v4l2_ctx vsi_v4l2_hwconfig.max_dec_resolution <= 1920) continue; } - if (inputformat != V4L2_DAEMON_CODEC_DEC_JPEG && - isJpegOnlyFmt(outfmt)) - continue; if (test_bit(CTX_FLAG_SRCCHANGED_BIT, &ctx->flag)) { + if (inputformat == V4L2_DAEMON_CODEC_DEC_JPEG && + outfmt != ctx->mediacfg.decparams.dec_info.dec_info.src_pix_fmt) + continue; if ((outfmt == VSI_V4L2_DECOUT_NV12_10BIT || outfmt == VSI_V4L2_DECOUT_P010) && ctx->mediacfg.decparams.dec_info.dec_info.bit_depth < 10) @@ -1000,15 +997,15 @@ static void verifyPlanesize(unsigned int psize[], int braw, int pixelformat, int extsize = basesize / 2; quadsize = basesize / 4; break; - case V4L2_PIX_FMT_422SP: + case V4L2_PIX_FMT_NV16: extsize = basesize; quadsize = 0; break; - case V4L2_PIX_FMT_444SP: + case V4L2_PIX_FMT_NV24: extsize = basesize * 2; quadsize = 0; break; - case V4L2_PIX_FMT_400: + case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_YUYV: extsize = 0; quadsize = 0; @@ -1671,7 +1668,6 @@ void vsiv4l2_set_hwinfo(struct vsi_v4l2_dev_info *hwinfo) if (((1 << i) & hwinfo->encformat) == 0) vsi_coded_fmt[i].enc_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE; if (((1 << i) & hwinfo->decformat) == 0) { - vsi_coded_fmt[i].dec_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE; //disable all jpg only output fmt if (vsi_coded_fmt[i].dec_fmt == V4L2_DAEMON_CODEC_DEC_JPEG) { for (j = 0; j < ARRAY_SIZE(vsi_raw_fmt); j++) { @@ -1679,6 +1675,7 @@ void vsiv4l2_set_hwinfo(struct vsi_v4l2_dev_info *hwinfo) vsi_raw_fmt[j].dec_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE; } } + vsi_coded_fmt[i].dec_fmt = V4L2_DAEMON_CODEC_UNKNOW_TYPE; } } } diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2-dec.c b/drivers/mxc/hantro_v4l2/vsi-v4l2-dec.c index 55c1f054972d..2caef9c77ffc 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2-dec.c +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2-dec.c @@ -116,10 +116,13 @@ static int vsi_dec_s_parm(struct file *filp, void *priv, struct v4l2_streamparm if (!isvalidtype(parm->type, ctx->flag)) return -EINVAL; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; if (binputqueue(parm->type)) ctx->mediacfg.outputparam = parm->parm.output; else ctx->mediacfg.capparam = parm->parm.capture; + mutex_unlock(&ctx->ctxlock); return 0; } @@ -155,6 +158,7 @@ static int vsi_dec_g_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vsi_dec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) { + int ret; struct vsi_v4l2_ctx *ctx = fh_to_ctx(file->private_data); v4l2_klog(LOGLVL_CONFIG, "%lx:%s:%d", ctx->ctxid, __func__, f->type); @@ -163,7 +167,11 @@ static int vsi_dec_s_fmt(struct file *file, void *priv, struct v4l2_format *f) if (!isvalidtype(f->type, ctx->flag)) return -EINVAL; - return vsiv4l2_setfmt(ctx, f); + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + ret = vsiv4l2_setfmt(ctx, f); + mutex_unlock(&ctx->ctxlock); + return ret; } static int vsi_dec_querybuf( @@ -203,13 +211,18 @@ static int vsi_dec_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) return -ENODEV; if (!isvalidtype(buf->type, ctx->flag)) return -EINVAL; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + if (binputqueue(buf->type)) + set_bit(CTX_FLAG_SRCBUF_BIT, &ctx->flag); if (binputqueue(buf->type) && buf->bytesused == 0 && ctx->status == DEC_STATUS_DECODING) { if (test_and_clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag)) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, NULL); - ctx_switchstate(ctx, DEC_STATUS_DRAINING); + ctx->status = DEC_STATUS_DRAINING; } else ret = 0; + mutex_unlock(&ctx->ctxlock); return ret; } if (!binputqueue(buf->type)) { @@ -222,11 +235,24 @@ static int vsi_dec_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) } if (ret == 0 && ctx->status == VSI_STATUS_INIT && ctx->input_que.queued_count >= ctx->input_que.min_buffers_needed - && ctx->input_que.streaming) { + && vb2_is_streaming(&ctx->input_que)) { v4l2_klog(LOGLVL_FLOW, "%lx:%s start streaming", ctx->ctxid, __func__); - ctx_switchstate(ctx, DEC_STATUS_DECODING); + ctx->status = DEC_STATUS_DECODING; ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMON_OUTPUT, NULL); } + mutex_unlock(&ctx->ctxlock); + return ret; +} + +static int vsi_dec_dec2drain(struct vsi_v4l2_ctx *ctx) +{ + int ret = 0; + + if (ctx->status == DEC_STATUS_DECODING && + test_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag)) { + ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, NULL); + ctx->status = DEC_STATUS_DRAINING; + } return ret; } @@ -235,35 +261,41 @@ static int vsi_dec_streamon(struct file *filp, void *priv, enum v4l2_buf_type ty int ret = 0; struct vsi_v4l2_ctx *ctx = fh_to_ctx(filp->private_data); - v4l2_klog(LOGLVL_BRIEF, "%lx %s:%d", ctx->ctxid, __func__, type); if (!vsi_v4l2_daemonalive()) return -ENODEV; if (!isvalidtype(type, ctx->flag)) return -EINVAL; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + v4l2_klog(LOGLVL_BRIEF, "%lx %s:%d in status %d", ctx->ctxid, __func__, type, ctx->status); if (!binputqueue(type)) { ret = vb2_streamon(&ctx->output_que, type); if (ret == 0) { - ctx_switchstate(ctx, DEC_STATUS_DECODING); + if (ctx->status != DEC_STATUS_SEEK && ctx->status != DEC_STATUS_ENDSTREAM) + ctx->status = DEC_STATUS_DECODING; ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMON_CAPTURE, NULL); - if (ret == 0) { - if (ctx->status != DEC_STATUS_DRAINING && - test_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag)) { - ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, NULL); - ctx_switchstate(ctx, DEC_STATUS_DRAINING); - } + if (ret == 0) + vsi_dec_dec2drain(ctx); + if (test_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag)) { + struct vb2_buffer *vb = ctx->output_que.bufs[0]; + vb->planes[0].bytesused = 0; + ctx->lastcapbuffer_idx = 0; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); } } printbufinfo(&ctx->output_que); } else { ret = vb2_streamon(&ctx->input_que, type); if (ret == 0 && ctx->input_que.queued_count >= ctx->input_que.min_buffers_needed) { - ctx_switchstate(ctx, DEC_STATUS_DECODING); + ctx->status = DEC_STATUS_DECODING; ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMON_OUTPUT, NULL); + if (ret == 0) + vsi_dec_dec2drain(ctx); } printbufinfo(&ctx->input_que); } - + mutex_unlock(&ctx->ctxlock); return ret; } @@ -271,14 +303,18 @@ static int vsi_checkctx_srcbuf(struct vsi_v4l2_ctx *ctx) { int ret = 0; - if (mutex_lock_interruptible(&ctx->ctxlock)) - return 1; if (ctx->queued_srcnum == 0 || ctx->error < 0) ret = 1; - mutex_unlock(&ctx->ctxlock); return ret; } +static int vsi_checkctx_capoffdone(struct vsi_v4l2_ctx *ctx) +{ + if (test_and_clear_bit(CTX_FLAG_STREAMOFFDONE, &ctx->flag)) + return 1; + return 0; +} + static void vsi_dec_update_reso(struct vsi_v4l2_ctx *ctx) { struct vsi_v4l2_mediacfg *pcfg = &ctx->mediacfg; @@ -304,7 +340,6 @@ static int vsi_dec_streamoff( struct vb2_queue *q; enum v4l2_buf_type otype; - v4l2_klog(LOGLVL_BRIEF, "%lx %s:%d", ctx->ctxid, __func__, type); if (!vsi_v4l2_daemonalive()) return -ENODEV; if (ctx->error < 0) @@ -319,37 +354,53 @@ static int vsi_dec_streamoff( else q = &ctx->output_que; - if (q->streaming == 0 && ctx->status == VSI_STATUS_INIT) + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + v4l2_klog(LOGLVL_BRIEF, "%lx %s:%d:%d:%d", ctx->ctxid, __func__, type, ctx->status, ctx->queued_srcnum); + if (!vb2_is_streaming(q) && ctx->status == VSI_STATUS_INIT) { + mutex_unlock(&ctx->ctxlock); return 0; + } if (binputqueue(type)) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMOFF_OUTPUT, NULL); - ctx_switchstate(ctx, DEC_STATUS_SEEK); + ctx->status = DEC_STATUS_SEEK; } else { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMOFF_CAPTURE, NULL); - if (ctx->status != DEC_STATUS_SEEK) - ctx_switchstate(ctx, DEC_STATUS_STOPPED); + if (ctx->status != DEC_STATUS_SEEK && ctx->status != DEC_STATUS_ENDSTREAM) + ctx->status = DEC_STATUS_STOPPED; } if (binputqueue(type)) { if (!(test_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag))) { + //here we need to wait all OUTPUT buffer returned + mutex_unlock(&ctx->ctxlock); if (wait_event_interruptible(ctx->retbuf_queue, vsi_checkctx_srcbuf(ctx) != 0)) - return -ERESTARTSYS; - } else { - clear_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag); - clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); + ret = -ERESTARTSYS; + if (mutex_lock_interruptible(&ctx->ctxlock)) + ret = -EBUSY; } - if (test_and_clear_bit(CTX_FLAG_DELAY_SRCCHANGED_BIT, &ctx->flag)) { + clear_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag); + clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); + clear_bit(CTX_FLAG_SRCBUF_BIT, &ctx->flag); + if (ret == 0 && test_and_clear_bit(CTX_FLAG_DELAY_SRCCHANGED_BIT, &ctx->flag)) { vsi_dec_update_reso(ctx); vsi_v4l2_send_reschange(ctx); v4l2_klog(LOGLVL_BRIEF, "%lx send delayed src change in streamoff", ctx->ctxid); } } else { + mutex_unlock(&ctx->ctxlock); + if (wait_event_interruptible(ctx->capoffdone_queue, + vsi_checkctx_capoffdone(ctx) != 0)) + ret = -ERESTARTSYS; + if (mutex_lock_interruptible(&ctx->ctxlock)) + ret = -EBUSY; ctx->buffed_capnum = 0; ctx->buffed_cropcapnum = 0; } return_all_buffers(q, VB2_BUF_STATE_DONE, 1); ret = vb2_streamoff(q, type); + mutex_unlock(&ctx->ctxlock); return ret; } @@ -371,16 +422,15 @@ static int vsi_dec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) else q = &ctx->output_que; - ret = vb2_dqbuf(q, p, file->f_flags & O_NONBLOCK); - if (ctx->status == DEC_STATUS_STOPPED) { - p->bytesused = 0; + if (!vb2_is_streaming(q)) return -EPIPE; - } + + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + ret = vb2_dqbuf(q, p, file->f_flags & O_NONBLOCK); if (ret == 0) { vb = q->bufs[p->index]; vsibuf = vb_to_vsibuf(vb); - if (mutex_lock_interruptible(&ctx->ctxlock)) - return -EBUSY; list_del(&vsibuf->list); if (!binputqueue(p->type)) { clear_bit(BUF_FLAG_DONE, &ctx->vbufflag[p->index]); @@ -388,11 +438,12 @@ static int vsi_dec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) ctx->buffed_cropcapnum--; } else clear_bit(BUF_FLAG_DONE, &ctx->srcvbufflag[p->index]); - mutex_unlock(&ctx->ctxlock); if (ctx->status != DEC_STATUS_ENDSTREAM && !(test_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag)) && - p->bytesused == 0) + p->bytesused == 0) { + mutex_unlock(&ctx->ctxlock); return -EAGAIN; + } } if (!binputqueue(p->type)) { p->reserved = ctx->rfc_luma_offset[p->index]; @@ -401,7 +452,7 @@ static int vsi_dec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) if (p->bytesused == 0 && (ctx->status == DEC_STATUS_ENDSTREAM || test_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag))) { p->flags |= V4L2_BUF_FLAG_LAST; - ctx_switchstate(ctx, DEC_STATUS_STOPPED); + ctx->status = DEC_STATUS_ENDSTREAM; clear_bit(CTX_FLAG_ENDOFSTRM_BIT, &ctx->flag); v4l2_klog(LOGLVL_BRIEF, "send eos flag"); } else if (test_bit(CTX_FLAG_DELAY_SRCCHANGED_BIT, &ctx->flag) && ctx->buffed_capnum == 0) { @@ -422,6 +473,7 @@ static int vsi_dec_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) p->field = V4L2_FIELD_NONE; } v4l2_klog(LOGLVL_FLOW, "%lx:%s:%d:%d:%x:%d", ctx->ctxid, __func__, p->type, p->index, p->flags, p->bytesused); + mutex_unlock(&ctx->ctxlock); return ret; } @@ -515,11 +567,13 @@ static int vsi_dec_set_selection(struct file *file, void *prv, struct v4l2_selec //NXP has no PP, so any crop like setting won't work for decoder if (!vsi_v4l2_daemonalive()) return -ENODEV; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; pcfg->decparams.dec_info.dec_info.visible_rect.left = s->r.left; pcfg->decparams.dec_info.dec_info.visible_rect.top = s->r.top; pcfg->decparams.dec_info.dec_info.visible_rect.width = s->r.width; pcfg->decparams.dec_info.dec_info.visible_rect.height = s->r.height; - + mutex_unlock(&ctx->ctxlock); v4l2_klog(LOGLVL_CONFIG, "%lx:%s:%d,%d,%d,%d", ctx->ctxid, __func__, s->r.left, s->r.top, s->r.width, s->r.height); return 0; @@ -556,6 +610,22 @@ static int vsi_dec_subscribe_event( return ret; } +static int vsi_dec_handlestop_unspec(struct vsi_v4l2_ctx *ctx) +{ + //some unexpected condition fro CTS, not quite conformant to spec + if ((ctx->status == VSI_STATUS_INIT && !test_bit(CTX_FLAG_DAEMONLIVE_BIT, &ctx->flag)) || + ctx->status == DEC_STATUS_STOPPED) { + clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); + vsi_v4l2_sendeos(ctx); + return 0; + } + if (ctx->status == DEC_STATUS_SEEK && !test_bit(CTX_FLAG_SRCBUF_BIT, &ctx->flag)) { + vsi_v4l2_sendeos(ctx); + return 0; + } + return 0; +} + int vsi_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct vsi_v4l2_ctx *ctx = fh_to_ctx(file->private_data); @@ -563,40 +633,35 @@ int vsi_dec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cm int ret = -EBUSY; v4l2_klog(LOGLVL_BRIEF, "%lx:%s:%d in state %d:%d", ctx->ctxid, __func__, - cmd->cmd, ctx->status, ctx->output_que.streaming); + cmd->cmd, ctx->status, vb2_is_streaming(&ctx->output_que)); if (!vsi_v4l2_daemonalive()) return -ENODEV; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; switch (cmd->cmd) { case V4L2_DEC_CMD_STOP: set_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); if (ctx->status == DEC_STATUS_DECODING) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, NULL); - ctx_switchstate(ctx, DEC_STATUS_DRAINING); - } else if ((ctx->status == VSI_STATUS_INIT && !test_bit(CTX_FLAG_DAEMONLIVE_BIT, &ctx->flag)) || - ctx->status == DEC_STATUS_STOPPED) { - struct v4l2_event event; - - clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); - memset((void *)&event, 0, sizeof(struct v4l2_event)); - event.type = V4L2_EVENT_EOS; - v4l2_event_queue_fh(&ctx->fh, &event); - ret = 0; - } + ctx->status = DEC_STATUS_DRAINING; + } else + ret = vsi_dec_handlestop_unspec(ctx); break; case V4L2_DEC_CMD_START: if (ctx->status == DEC_STATUS_STOPPED) { - ctx_switchstate(ctx, DEC_STATUS_DECODING); + ctx->status = DEC_STATUS_DECODING; ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_START, cmd); } break; case V4L2_DEC_CMD_RESET: - vsi_v4l2_reset_ctx(ctx); + ret = vsi_v4l2_reset_ctx(ctx); break; case V4L2_DEC_CMD_PAUSE: case V4L2_DEC_CMD_RESUME: default: break; } + mutex_unlock(&ctx->ctxlock); return ret; } @@ -670,9 +735,7 @@ static void vsi_dec_buf_queue(struct vb2_buffer *vb) struct vsi_vpu_buf *vsibuf; int ret; - v4l2_klog(LOGLVL_FLOW, "%s:%d", __func__, vb->index); - if (mutex_lock_interruptible(&ctx->ctxlock)) - return; + v4l2_klog(LOGLVL_FLOW, "%s:%d:%d", __func__, vq->type, vb->index); vsibuf = vb_to_vsibuf(vb); if (!binputqueue(vq->type)) { set_bit(BUF_FLAG_QUEUED, &ctx->vbufflag[vb->index]); @@ -682,7 +745,6 @@ static void vsi_dec_buf_queue(struct vb2_buffer *vb) list_add_tail(&vsibuf->list, &ctx->input_list); ctx->queued_srcnum++; } - mutex_unlock(&ctx->ctxlock); ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_BUF_RDY, vb); } @@ -753,6 +815,9 @@ static int vsi_v4l2_dec_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_DIS_REORDER: ctx->mediacfg.decparams.io_buffer.no_reordering_decoding = ctrl->val; break; + case V4L2_CID_SECUREMODE: + ctx->mediacfg.decparams.io_buffer.securemode_on = ctrl->val; + break; default: return 0; } @@ -901,6 +966,16 @@ static struct v4l2_ctrl_config vsi_v4l2_dec_ctrl_defs[] = { .step = 1, .def = 1, }, + { + .ops = &vsi_dec_ctrl_ops, + .id = V4L2_CID_SECUREMODE, + .name = "en/disable secure mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, }; static int vsi_dec_setup_ctrls(struct v4l2_ctrl_handler *handler) @@ -1017,7 +1092,7 @@ static int v4l2_dec_open(struct file *filp) vfh->ctrl_handler = &ctx->ctrlhdl; atomic_set(&ctx->srcframen, 0); atomic_set(&ctx->dstframen, 0); - ctx_switchstate(ctx, VSI_STATUS_INIT); + ctx->status = VSI_STATUS_INIT; //dev->vdev->queue = q; //single queue is used for v4l2 default ops such as ioctl, read, write and poll diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2-enc.c b/drivers/mxc/hantro_v4l2/vsi-v4l2-enc.c index c65ebe98e4d0..01cc58cb90b3 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2-enc.c +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2-enc.c @@ -48,7 +48,7 @@ static int vsi_enc_querycap( { struct vsi_v4l2_dev_info *hwinfo; - v4l2_klog(LOGLVL_FLOW, "%s", __func__); + v4l2_klog(LOGLVL_CONFIG, "%s", __func__); if (!vsi_v4l2_daemonalive()) return -ENODEV; hwinfo = vsiv4l2_get_hwinfo(); @@ -84,7 +84,9 @@ static int vsi_enc_reqbufs( else q = &ctx->output_que; ret = vb2_reqbufs(q, p); - v4l2_klog(LOGLVL_CONFIG, "%lx:%s:%d ask for %d buffer, got %d:%d:%d", + if (!binputqueue(p->type) && p->count == 0) + set_bit(CTX_FLAG_ENC_FLUSHBUF, &ctx->flag); + v4l2_klog(LOGLVL_BRIEF, "%lx:%s:%d ask for %d buffer, got %d:%d:%d", ctx->ctxid, __func__, p->type, p->count, q->num_buffers, ret, ctx->status); return ret; } @@ -109,6 +111,8 @@ static int vsi_enc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm if (!isvalidtype(parm->type, ctx->flag)) return -EINVAL; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; if (binputqueue(parm->type)) { ctx->mediacfg.encparams.general.inputRateNumer = parm->parm.output.timeperframe.denominator; ctx->mediacfg.encparams.general.inputRateDenom = parm->parm.output.timeperframe.numerator; @@ -119,6 +123,7 @@ static int vsi_enc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm ctx->mediacfg.capparam = parm->parm.capture; } set_bit(CTX_FLAG_CONFIGUPDATE_BIT, &ctx->flag); + mutex_unlock(&ctx->ctxlock); return 0; } @@ -161,8 +166,11 @@ static int vsi_enc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) return -ENODEV; if (!isvalidtype(f->type, ctx->flag)) return -EINVAL; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; ret = vsiv4l2_setfmt(ctx, f); set_bit(CTX_FLAG_CONFIGUPDATE_BIT, &ctx->flag); + mutex_unlock(&ctx->ctxlock); return ret; } @@ -196,35 +204,21 @@ static int vsi_enc_querybuf( static int vsi_enc_trystartenc(struct vsi_v4l2_ctx *ctx) { int ret = 0; - struct vsi_queued_buf *buf, *node; - struct video_device *vdev = ctx->dev->venc; v4l2_klog(LOGLVL_BRIEF, "%s:streaming:%d:%d, queued buf:%d:%d", __func__, ctx->input_que.streaming, ctx->output_que.streaming, ctx->input_que.queued_count, ctx->output_que.queued_count); - if (ctx->input_que.streaming && ctx->output_que.streaming) { - if (!list_empty(&ctx->queued_list)) { - list_for_each_entry_safe(buf, node, &ctx->queued_list, list) { - if (!binputqueue(buf->qb.type)) - ret = vb2_qbuf(&ctx->output_que, vdev->v4l2_dev->mdev, &buf->qb); - else - ret = vb2_qbuf(&ctx->input_que, vdev->v4l2_dev->mdev, &buf->qb); - list_del(&buf->list); - vfree(buf); - } - } + if (vb2_is_streaming(&ctx->input_que) && vb2_is_streaming(&ctx->output_que)) { if ((ctx->status == VSI_STATUS_INIT || - ctx->status == ENC_STATUS_STOPPED || - ctx->status == ENC_STATUS_STOPPED_BYUSR || - ctx->status == ENC_STATUS_RESET) && + ctx->status == ENC_STATUS_STOPPED) && ctx->input_que.queued_count >= ctx->input_que.min_buffers_needed && ctx->output_que.queued_count >= ctx->output_que.min_buffers_needed) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMON, NULL); if (ret == 0) { - ctx_switchstate(ctx, ENC_STATUS_ENCODING); + ctx->status = ENC_STATUS_ENCODING; if (test_and_clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag)) { ret |= vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, NULL); - ctx_switchstate(ctx, ENC_STATUS_DRAINING); + ctx->status = ENC_STATUS_DRAINING; } } } @@ -232,35 +226,6 @@ static int vsi_enc_trystartenc(struct vsi_v4l2_ctx *ctx) return ret; } -static int bufto_queuelist(struct vsi_v4l2_ctx *ctx, struct v4l2_buffer *buf) -{ - struct vsi_queued_buf *qb; - struct vsi_v4l2_mediacfg *pcfg = &ctx->mediacfg; - int i, planeno = (binputqueue(buf->type) ? pcfg->srcplanes : pcfg->dstplanes); - - qb = vmalloc(sizeof(struct vsi_queued_buf)); - if (qb == NULL) - return -ENOMEM; - qb->qb = *buf; - for (i = 0; i < planeno; i++) - qb->planes[i] = buf->m.planes[i]; - qb->qb.m.planes = qb->planes; - list_add_tail(&qb->list, &ctx->queued_list); - return 0; -} - -static void clear_quelist(struct vsi_v4l2_ctx *ctx) -{ - struct vsi_queued_buf *buf, *node; - - if (!list_empty(&ctx->queued_list)) { - list_for_each_entry_safe(buf, node, &ctx->queued_list, list) { - list_del(&buf->list); - vfree(buf); - } - } -} - static int vsi_enc_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) { int ret; @@ -272,13 +237,15 @@ static int vsi_enc_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) return -ENODEV; if (!isvalidtype(buf->type, ctx->flag)) return -EINVAL; - if (ctx->status == ENC_STATUS_STOPPED_BYUSR) + + //ignore input buf in spec's STOP state + if (binputqueue(buf->type) && + (ctx->status == ENC_STATUS_STOPPED) && + !vb2_is_streaming(&ctx->input_que)) return 0; - if ((ctx->status == ENC_STATUS_STOPPED || - ctx->status == ENC_STATUS_RESET || - ctx->status == ENC_STATUS_DRAINING) && - binputqueue(buf->type)) - return bufto_queuelist(ctx, buf); + + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; if (!binputqueue(buf->type)) ret = vb2_qbuf(&ctx->output_que, vdev->v4l2_dev->mdev, buf); @@ -292,10 +259,9 @@ static int vsi_enc_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf) ctx->ctxid, __func__, buf->type, buf->index, buf->bytesused, buf->m.planes[0].bytesused, buf->m.planes[0].length, buf->m.planes[1].bytesused, buf->m.planes[1].length); - if (ret == 0 && ctx->status != ENC_STATUS_ENCODING && - ctx->status != ENC_STATUS_STOPPED) + if (ret == 0 && ctx->status != ENC_STATUS_ENCODING) ret = vsi_enc_trystartenc(ctx); - + mutex_unlock(&ctx->ctxlock); return ret; } @@ -312,6 +278,8 @@ static int vsi_enc_streamon(struct file *filp, void *priv, enum v4l2_buf_type ty if (ctx->status == ENC_STATUS_ENCODING) return 0; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; if (!binputqueue(type)) { ret = vb2_streamon(&ctx->output_que, type); printbufinfo(&ctx->output_que); @@ -320,12 +288,10 @@ static int vsi_enc_streamon(struct file *filp, void *priv, enum v4l2_buf_type ty printbufinfo(&ctx->input_que); } - if (ret == 0) { - if (ctx->status == ENC_STATUS_STOPPED_BYUSR) - ctx_switchstate(ctx, ENC_STATUS_STOPPED); + if (ret == 0) ret = vsi_enc_trystartenc(ctx); - } + mutex_unlock(&ctx->ctxlock); return ret; } @@ -343,24 +309,27 @@ static int vsi_enc_streamoff( return -ENODEV; if (!isvalidtype(type, ctx->flag)) return -EINVAL; + if (ctx->status == VSI_STATUS_INIT) + return 0; if (binputqueue(type)) q = &ctx->input_que; else q = &ctx->output_que; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; return_all_buffers(q, VB2_BUF_STATE_DONE, 1); ret = vb2_streamoff(q, type); if (ret == 0) { + ctx->status = ENC_STATUS_STOPPED; if (binputqueue(type)) { - ctx_switchstate(ctx, ENC_STATUS_STOPPED_BYUSR); - clear_quelist(ctx); clear_bit(CTX_FLAG_FORCEIDR_BIT, &ctx->flag); for (i = 0; i < VIDEO_MAX_FRAME; i++) ctx->srcvbufflag[i] = 0; - } else - ctx_switchstate(ctx, ENC_STATUS_RESET); + } } + mutex_unlock(&ctx->ctxlock); return ret; } @@ -371,7 +340,6 @@ static int vsi_enc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) struct vb2_queue *q; struct vb2_buffer *vb; struct vsi_vpu_buf *vsibuf; - struct v4l2_event event; if (!vsi_v4l2_daemonalive()) return -ENODEV; @@ -382,20 +350,18 @@ static int vsi_enc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) else q = &ctx->output_que; - if (ctx->status == ENC_STATUS_STOPPED_BYUSR || - ctx->status == ENC_STATUS_STOPPED) { + if (ctx->status == ENC_STATUS_STOPPED) { p->bytesused = 0; return -EPIPE; } - ret = vb2_dqbuf(q, p, file->f_flags & O_NONBLOCK); + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + ret = vb2_dqbuf(q, p, file->f_flags & O_NONBLOCK); if (ret == 0) { vb = q->bufs[p->index]; vsibuf = vb_to_vsibuf(vb); - if (mutex_lock_interruptible(&ctx->ctxlock)) - return -EBUSY; list_del(&vsibuf->list); - mutex_unlock(&ctx->ctxlock); p->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); if (!binputqueue(p->type)) { if (ctx->vbufflag[p->index] & FRAMETYPE_I) @@ -410,15 +376,14 @@ static int vsi_enc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) if (ret == 0) { if (ctx->vbufflag[p->index] & LAST_BUFFER_FLAG) { p->flags |= V4L2_BUF_FLAG_LAST; - memset((void *)&event, 0, sizeof(struct v4l2_event)); - event.type = V4L2_EVENT_EOS; - v4l2_event_queue_fh(&ctx->fh, &event); + vsi_v4l2_sendeos(ctx); if (ctx->status == ENC_STATUS_DRAINING) - ctx_switchstate(ctx, ENC_STATUS_STOPPED); + ctx->status = ENC_STATUS_STOPPED; v4l2_klog(LOGLVL_BRIEF, "dqbuf get eos flag"); } } } + mutex_unlock(&ctx->ctxlock); v4l2_klog(LOGLVL_FLOW, "%s:%d:%d:%d:%x:%d", __func__, p->type, p->index, ret, p->flags, ctx->status); return ret; } @@ -519,11 +484,14 @@ static int vsi_enc_set_selection(struct file *file, void *prv, struct v4l2_selec return -EINVAL; ret = vsiv4l2_verifycrop(s); if (!ret) { + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; pcfg->encparams.general.horOffsetSrc = s->r.left; pcfg->encparams.general.verOffsetSrc = s->r.top; pcfg->encparams.general.width = s->r.width; pcfg->encparams.general.height = s->r.height; set_bit(CTX_FLAG_CONFIGUPDATE_BIT, &ctx->flag); + mutex_unlock(&ctx->ctxlock); } v4l2_klog(LOGLVL_CONFIG, "%lx:%s:%d,%d,%d,%d", ctx->ctxid, __func__, s->r.left, s->r.top, s->r.width, s->r.height); @@ -580,39 +548,37 @@ static int vsi_enc_subscribe_event( static int vsi_enc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) { struct vsi_v4l2_ctx *ctx = fh_to_ctx(file->private_data); - //u32 flag = cmd->flags; - int ret = -EBUSY; + int ret = 0; - /// refer to https://linuxtv.org/downloads/v4l-dvb-apis/userspace-api/v4l/dev-encoder.html - v4l2_klog(LOGLVL_BRIEF, "%s:%d:%d", __func__, ctx->status, cmd->cmd); if (!vsi_v4l2_daemonalive()) return -ENODEV; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; + v4l2_klog(LOGLVL_BRIEF, "%s:%d:%d", __func__, ctx->status, cmd->cmd); switch (cmd->cmd) { case V4L2_ENC_CMD_STOP: set_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); if (ctx->status == ENC_STATUS_ENCODING) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_CMD_STOP, cmd); if (ret == 0) { - ctx_switchstate(ctx, ENC_STATUS_DRAINING); + ctx->status = ENC_STATUS_DRAINING; clear_bit(CTX_FLAG_PRE_DRAINING_BIT, &ctx->flag); } - } else if (ctx->status != ENC_STATUS_DRAINING) - ret = 0; + } break; case V4L2_ENC_CMD_START: - if (ctx->status == ENC_STATUS_STOPPED || - ctx->status == ENC_STATUS_STOPPED_BYUSR) { + if (ctx->status == ENC_STATUS_STOPPED) { vb2_streamon(&ctx->input_que, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); vb2_streamon(&ctx->input_que, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); ret = vsi_enc_trystartenc(ctx); - } else if (ctx->status == ENC_STATUS_ENCODING) - ret = 0; + } break; case V4L2_ENC_CMD_PAUSE: case V4L2_ENC_CMD_RESUME: default: break; } + mutex_unlock(&ctx->ctxlock); return ret; } @@ -717,15 +683,12 @@ static void vsi_enc_buf_queue(struct vb2_buffer *vb) struct vsi_vpu_buf *vsibuf; int ret; - v4l2_klog(LOGLVL_FLOW, "%s:%d", __func__, vb->index); - if (mutex_lock_interruptible(&ctx->ctxlock)) - return; + v4l2_klog(LOGLVL_FLOW, "%s:%d:%d", __func__, vb->type, vb->index); vsibuf = vb_to_vsibuf(vb); if (!binputqueue(vq->type)) list_add_tail(&vsibuf->list, &ctx->output_list); else list_add_tail(&vsibuf->list, &ctx->input_list); - mutex_unlock(&ctx->ctxlock); ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_BUF_RDY, vb); } @@ -1209,16 +1172,16 @@ static struct v4l2_ctrl_config vsi_v4l2_encctrl_defs[] = { { .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 51, + .min = -1, + .max = 127, .step = 1, .def = DEFAULT_QP, }, { .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP, .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 51, + .min = -1, + .max = 127, .step = 1, .def = DEFAULT_QP, }, @@ -1304,6 +1267,7 @@ static int v4l2_enc_open(struct file *filp) mutex_init(&ctx->ctxlock); ctx->flag = CTX_FLAG_ENC; set_bit(CTX_FLAG_CONFIGUPDATE_BIT, &ctx->flag); + set_bit(CTX_FLAG_ENC_FLUSHBUF, &ctx->flag); ctx->frameidx = 0; q = &ctx->input_que; @@ -1340,14 +1304,13 @@ static int v4l2_enc_open(struct file *filp) vb2_queue_release(&ctx->input_que); goto err_enc_dec_exit; } - INIT_LIST_HEAD(&ctx->queued_list); vsiv4l2_initcfg(ctx); vsi_setup_enc_ctrls(&ctx->ctrlhdl); vfh = (struct v4l2_fh *)filp->private_data; vfh->ctrl_handler = &ctx->ctrlhdl; atomic_set(&ctx->srcframen, 0); atomic_set(&ctx->dstframen, 0); - ctx_switchstate(ctx, VSI_STATUS_INIT); + ctx->status = VSI_STATUS_INIT; return 0; diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2-priv.h b/drivers/mxc/hantro_v4l2/vsi-v4l2-priv.h index e5e97ca41ae5..bd0a727353a1 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2-priv.h +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2-priv.h @@ -155,8 +155,6 @@ enum CTX_STATUS { ENC_STATUS_ENCODING, ENC_STATUS_DRAINING, ENC_STATUS_STOPPED, - ENC_STATUS_STOPPED_BYUSR, - ENC_STATUS_RESET, DEC_STATUS_DECODING, DEC_STATUS_DRAINING, @@ -279,6 +277,9 @@ enum { CTX_FLAG_FORCEIDR_BIT, // force idr invoked CTX_FLAG_SRCCHANGED_BIT, // src change has come from daemon CTX_FLAG_DELAY_SRCCHANGED_BIT, // src change has come from daemon but not sent to app + CTX_FLAG_SRCBUF_BIT, // if any src buf comes from last OUTPUT off or INIT + CTX_FLAG_ENC_FLUSHBUF, // if any src buf comes from last OUTPUT off or INIT + CTX_FLAG_STREAMOFFDONE, // dec daemon finish handling capoff }; /* flag for decoder buffer*/ @@ -316,12 +317,11 @@ struct vsi_v4l2_ctx { u32 buffed_cropcapnum; u32 lastcapbuffer_idx; //latest received capture buffer index - struct list_head queued_list; - struct vsi_v4l2_mediacfg mediacfg; struct v4l2_ctrl_handler ctrlhdl; wait_queue_head_t retbuf_queue; + wait_queue_head_t capoffdone_queue; uint64_t frameidx; @@ -340,8 +340,10 @@ int vsi_v4l2_reset_ctx(struct vsi_v4l2_ctx *ctx); int vsi_v4l2_send_reschange(struct vsi_v4l2_ctx *ctx); int vsi_v4l2_notify_reschange(struct vsi_v4l2_msg *pmsg); int vsi_v4l2_handle_warningmsg(struct vsi_v4l2_msg *pmsg); +int vsi_v4l2_handle_streamoffdone(struct vsi_v4l2_msg *pmsg); int vsi_v4l2_handle_cropchange(struct vsi_v4l2_msg *pmsg); int vsi_v4l2_bufferdone(struct vsi_v4l2_msg *pmsg); +void vsi_v4l2_sendeos(struct vsi_v4l2_ctx *ctx); int vsi_v4l2_handleerror(unsigned long ctxtid, int error); int vsi_v4l2_handle_picconsumed(struct vsi_v4l2_msg *pmsg); struct video_device *vsi_v4l2_probe_enc( @@ -537,15 +539,6 @@ static inline int inst_isactive(struct vsi_v4l2_ctx *ctx) return 0; } -static inline int ctx_switchstate(struct vsi_v4l2_ctx *ctx, int state) -{ - if (mutex_lock_interruptible(&ctx->ctxlock)) - return -EBUSY; - ctx->status = state; - mutex_unlock(&ctx->ctxlock); - return 0; -} - static inline void return_all_buffers(struct vb2_queue *vq, int status, int bRelbuf) { int i; @@ -554,8 +547,7 @@ static inline void return_all_buffers(struct vb2_queue *vq, int status, int bRel struct list_head *plist; v4l2_klog(LOGLVL_FLOW, "%s", __func__); - if (mutex_lock_interruptible(&ctx->ctxlock)) - return; + if (binputqueue(vq->type)) plist = &ctx->input_list; else @@ -575,7 +567,6 @@ static inline void return_all_buffers(struct vb2_queue *vq, int status, int bRel v4l2_klog(LOGLVL_FLOW, "clear buffer %d", buf->vb.vb2_buf.index); } } - mutex_unlock(&ctx->ctxlock); } static inline void print_queinfo(struct vb2_queue *q) diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2.c b/drivers/mxc/hantro_v4l2/vsi-v4l2.c index cff43068e7a5..2253f98ed9fa 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2.c +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2.c @@ -134,6 +134,7 @@ struct vsi_v4l2_ctx *vsi_create_ctx(void) } mutex_unlock(&vsi_ctx_array_lock); init_waitqueue_head(&ctx->retbuf_queue); + init_waitqueue_head(&ctx->capoffdone_queue); return ctx; } @@ -160,6 +161,7 @@ void wakeup_ctxqueues(void) wake_up_interruptible_all(&ctx->input_que.done_wq); wake_up_interruptible_all(&ctx->output_que.done_wq); wake_up_interruptible_all(&ctx->retbuf_queue); + wake_up_interruptible_all(&ctx->capoffdone_queue); wake_up_interruptible_all(&ctx->fh.wait); } } @@ -190,18 +192,22 @@ int vsi_v4l2_reset_ctx(struct vsi_v4l2_ctx *ctx) if (isdecoder(ctx)) { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_DESTROY_DEC, NULL); ctx->queued_srcnum = ctx->buffed_capnum = ctx->buffed_cropcapnum = 0; - wake_up_interruptible_all(&ctx->retbuf_queue); ctx->flag = CTX_FLAG_DEC; } else { ret = vsiv4l2_execcmd(ctx, V4L2_DAEMON_VIDIOC_STREAMOFF, NULL); ctx->flag = CTX_FLAG_ENC; + set_bit(CTX_FLAG_ENC_FLUSHBUF, &ctx->flag); } set_bit(CTX_FLAG_CONFIGUPDATE_BIT, &ctx->flag); return_all_buffers(&ctx->input_que, VB2_BUF_STATE_DONE, 0); return_all_buffers(&ctx->output_que, VB2_BUF_STATE_DONE, 0); removeallcropinfo(ctx); - ctx_switchstate(ctx, VSI_STATUS_INIT); + ctx->status = VSI_STATUS_INIT; vsi_set_ctx_error(ctx, 0); + if (isdecoder(ctx)) { + wake_up_interruptible_all(&ctx->retbuf_queue); + wake_up_interruptible_all(&ctx->capoffdone_queue); + } } return ret; } @@ -239,23 +245,30 @@ int vsi_v4l2_handle_picconsumed(struct vsi_v4l2_msg *pmsg) return 0; } +void vsi_v4l2_sendeos(struct vsi_v4l2_ctx *ctx) +{ + struct v4l2_event event; + + memset((void *)&event, 0, sizeof(struct v4l2_event)); + event.type = V4L2_EVENT_EOS; + v4l2_event_queue_fh(&ctx->fh, &event); +} + int vsi_v4l2_handleerror(unsigned long ctxid, int error) { struct vsi_v4l2_ctx *ctx; - struct v4l2_event event; v4l2_klog(LOGLVL_ERROR, "%lx got error %d", ctxid, error); ctx = find_ctx(ctxid); if (ctx == NULL) return -1; - if (error == DAEMON_ERR_DEC_METADATA_ONLY) { - memset((void *)&event, 0, sizeof(struct v4l2_event)); - event.type = V4L2_EVENT_EOS; - v4l2_event_queue_fh(&ctx->fh, &event); - } else { + if (error == DAEMON_ERR_DEC_METADATA_ONLY) + vsi_v4l2_sendeos(ctx); + else { vsi_set_ctx_error(ctx, error > 0 ? -error:error); wake_up_interruptible_all(&ctx->retbuf_queue); + wake_up_interruptible_all(&ctx->capoffdone_queue); wake_up_interruptible_all(&ctx->input_que.done_wq); wake_up_interruptible_all(&ctx->output_que.done_wq); wake_up_interruptible_all(&ctx->fh.wait); @@ -299,6 +312,8 @@ int vsi_v4l2_notify_reschange(struct vsi_v4l2_msg *pmsg) struct vsi_v4l2_mediacfg *pcfg = &ctx->mediacfg; struct v4l2_daemon_dec_info *decinfo = &pmsg->params.dec_params.dec_info.dec_info; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; v4l2_klog(LOGLVL_BRIEF, "%lx sending event res change:%d, delay=%d", ctx->ctxid, ctx->status, (ctx->status == DEC_STATUS_DECODING || ctx->status == DEC_STATUS_DRAINING) && !list_empty(&ctx->output_que.done_list)); v4l2_klog(LOGLVL_BRIEF, "reso=%d:%d,bitdepth=%d,dpb=%d:%d,orig yuvfmt=%d", @@ -332,6 +347,7 @@ int vsi_v4l2_notify_reschange(struct vsi_v4l2_msg *pmsg) if (pmsg->params.dec_params.dec_info.dec_info.colour_description_present_flag) vsi_dec_updatevui(&pmsg->params.dec_params.dec_info.dec_info, &pcfg->decparams.dec_info.dec_info); set_bit(CTX_FLAG_SRCCHANGED_BIT, &ctx->flag); + mutex_unlock(&ctx->ctxlock); } return 0; } @@ -367,6 +383,20 @@ int vsi_v4l2_handle_warningmsg(struct vsi_v4l2_msg *pmsg) return 0; } +int vsi_v4l2_handle_streamoffdone(struct vsi_v4l2_msg *pmsg) +{ + unsigned long ctxid = pmsg->inst_id; + struct vsi_v4l2_ctx *ctx; + + ctx = find_ctx(ctxid); + if (ctx == NULL) + return -ESRCH; + set_bit(CTX_FLAG_STREAMOFFDONE, &ctx->flag); + wake_up_interruptible_all(&ctx->capoffdone_queue); + v4l2_klog(LOGLVL_FLOW, "%lx got cap streamoff done", ctxid); + return 0; +} + int vsi_v4l2_handle_cropchange(struct vsi_v4l2_msg *pmsg) { unsigned long ctxid = pmsg->inst_id; @@ -380,6 +410,8 @@ int vsi_v4l2_handle_cropchange(struct vsi_v4l2_msg *pmsg) struct vsi_v4l2_mediacfg *pcfg = &ctx->mediacfg; struct v4l2_event event; + if (mutex_lock_interruptible(&ctx->ctxlock)) + return -EBUSY; v4l2_klog(LOGLVL_BRIEF, "%lx sending crop change:%d:%d:%d", ctx->ctxid, ctx->status, ctx->buffed_cropcapnum, ctx->lastcapbuffer_idx); v4l2_klog(LOGLVL_BRIEF, "crop info:%d:%d:%d:%d:%d:%d:%d", pmsg->params.dec_params.pic_info.pic_info.width, @@ -410,6 +442,7 @@ int vsi_v4l2_handle_cropchange(struct vsi_v4l2_msg *pmsg) event.type = V4L2_EVENT_CROPCHANGE, v4l2_event_queue_fh(&ctx->fh, &event); } + mutex_unlock(&ctx->ctxlock); } return 0; } @@ -441,13 +474,12 @@ int vsi_v4l2_bufferdone(struct vsi_v4l2_msg *pmsg) if (inbufidx >= 0 && inbufidx < ctx->input_que.num_buffers) { vq = &ctx->input_que; vb = vq->bufs[inbufidx]; - atomic_inc(&ctx->srcframen); if (mutex_lock_interruptible(&ctx->ctxlock)) return -1; + atomic_inc(&ctx->srcframen); if (ctx->input_que.streaming && vb->state == VB2_BUF_STATE_ACTIVE) vb2_buffer_done(vb, VB2_BUF_STATE_DONE); ctx->queued_srcnum--; - mutex_unlock(&ctx->ctxlock); if (isdecoder(ctx)) { if (!test_bit(BUF_FLAG_QUEUED, &ctx->srcvbufflag[inbufidx])) { v4l2_klog(LOGLVL_WARNING, "got unqueued srcbuf %d", inbufidx); @@ -456,6 +488,7 @@ int vsi_v4l2_bufferdone(struct vsi_v4l2_msg *pmsg) set_bit(BUF_FLAG_DONE, &ctx->srcvbufflag[inbufidx]); } } + mutex_unlock(&ctx->ctxlock); if (ctx->queued_srcnum == 0) wake_up_interruptible_all(&ctx->retbuf_queue); } @@ -463,19 +496,18 @@ int vsi_v4l2_bufferdone(struct vsi_v4l2_msg *pmsg) if (mutex_lock_interruptible(&ctx->ctxlock)) return -EBUSY; if (!inst_isactive(ctx)) { + if (!vb2_is_streaming(&ctx->output_que)) + v4l2_klog(LOGLVL_ERROR, "%lx ignore dst buffer %d in state %d", ctx->ctxid, outbufidx, ctx->status); mutex_unlock(&ctx->ctxlock); return 0; } if (bytesused[0] > 0) ctx->frameidx++; - mutex_unlock(&ctx->ctxlock); vq = &ctx->output_que; vb = vq->bufs[outbufidx]; atomic_inc(&ctx->dstframen); if (vb->state == VB2_BUF_STATE_ACTIVE) { vb->planes[0].bytesused = bytesused[0]; - if (mutex_lock_interruptible(&ctx->ctxlock)) - return -EBUSY; if (isencoder(ctx)) { vb->timestamp = pmsg->params.enc_params.io_buffer.timestamp; ctx->vbufflag[outbufidx] = pmsg->param_type; @@ -510,8 +542,10 @@ int vsi_v4l2_bufferdone(struct vsi_v4l2_msg *pmsg) } if (vb->state == VB2_BUF_STATE_ACTIVE) vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - mutex_unlock(&ctx->ctxlock); + else + v4l2_klog(LOGLVL_WARNING, "dstbuf %d is not active", outbufidx); } + mutex_unlock(&ctx->ctxlock); } return 0; } diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2.h b/drivers/mxc/hantro_v4l2/vsi-v4l2.h index 252a87cc9755..c29d19c63070 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2.h +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2.h @@ -126,6 +126,7 @@ enum v4l2_daemon_cmd_id { V4L2_DAEMON_VIDIOC_PICCONSUMED, V4L2_DAEMON_VIDIOC_CROPCHANGE, V4L2_DAEMON_VIDIOC_WARNONOPTION, + V4L2_DAEMON_VIDIOC_STREAMOFF_CAPTURE_DONE, V4L2_DAEMON_VIDIOC_TOTAL_AMOUNT, }; @@ -515,6 +516,7 @@ struct v4l2_daemon_dec_buffers { s64 timestamp; s32 no_reordering_decoding; + s32 securemode_on; }; //stub struct diff --git a/drivers/mxc/hantro_v4l2/vsi-v4l2daemon.c b/drivers/mxc/hantro_v4l2/vsi-v4l2daemon.c index 87a7be9bae95..6d54fa5f29c4 100755 --- a/drivers/mxc/hantro_v4l2/vsi-v4l2daemon.c +++ b/drivers/mxc/hantro_v4l2/vsi-v4l2daemon.c @@ -262,7 +262,6 @@ static int vsi_v4l2_sendcmd( if (wait_event_interruptible(ret_queue, getRet(mid, &error, retflag) != 0)) return -ERESTARTSYS; } - return error; } @@ -416,6 +415,7 @@ static void format_bufinfo_dec(struct vsi_v4l2_ctx *ctx, struct vsi_v4l2_msg *pm int vsiv4l2_execcmd(struct vsi_v4l2_ctx *ctx, enum v4l2_daemon_cmd_id id, void *args) { int ret = 0; + u32 param = 0; s32 retflag; struct vsi_v4l2_msg msg; @@ -442,12 +442,14 @@ int vsiv4l2_execcmd(struct vsi_v4l2_ctx *ctx, enum v4l2_daemon_cmd_id id, void * if (ret == 0) { if ((retflag & LAST_BUFFER_FLAG) && ctx->status == ENC_STATUS_DRAINING) - ctx_switchstate(ctx, ENC_STATUS_STOPPED); + ctx->status = ENC_STATUS_STOPPED; } break; case V4L2_DAEMON_VIDIOC_STREAMON: + if (test_and_clear_bit(CTX_FLAG_ENC_FLUSHBUF, &ctx->flag)) + param = 1; ret = vsi_v4l2_sendcmd(id, ctx->ctxid, - ctx->mediacfg.encparams.general.codecFormat, NULL, &retflag, 0, 0); + ctx->mediacfg.encparams.general.codecFormat, NULL, &retflag, 0, param); break; case V4L2_DAEMON_VIDIOC_STREAMOFF_OUTPUT: ret = vsi_v4l2_sendcmd(id, ctx->ctxid, @@ -617,6 +619,8 @@ static int vsi_handle_daemonmsg(struct vsi_v4l2_msg *pmsg) return vsi_v4l2_handle_cropchange(pmsg); case V4L2_DAEMON_VIDIOC_WARNONOPTION: return vsi_v4l2_handle_warningmsg(pmsg); + case V4L2_DAEMON_VIDIOC_STREAMOFF_CAPTURE_DONE: + return vsi_v4l2_handle_streamoffdone(pmsg); default: return -EINVAL; } @@ -635,9 +639,6 @@ static ssize_t v4l2_msg_write(struct file *fh, const char __user *buf, size_t si v4l2_klog(LOGLVL_ERROR, "input data unaccessable"); return size; } - if (mutex_lock_interruptible(&ret_lock)) - return size; - pmsg = kzalloc(sizeof(struct vsi_v4l2_msg), GFP_KERNEL); if (copy_from_user((void *)pmsg, (void __user *)buf, sizeof(struct vsi_v4l2_msg_hdr)) != 0) { @@ -659,17 +660,20 @@ static ssize_t v4l2_msg_write(struct file *fh, const char __user *buf, size_t si v4l2_klog(LOGLVL_VERBOSE, "get msg id = %d, flag = %x, seqid = %lx, err = %d", pmsg->cmd_id, pmsg->param_type, pmsg->seq_id, pmsg->error); accubytes += sizeof(struct vsi_v4l2_msg_hdr) + msgsize; + if (pmsg->seq_id == NO_RESPONSE_SEQID) { - ret = 0; vsi_handle_daemonmsg(pmsg); kfree(pmsg); + return size; } else { + if (mutex_lock_interruptible(&ret_lock)) + return size; ret = idr_alloc(retarray, (void *)pmsg, 1, 0, GFP_KERNEL); + mutex_unlock(&ret_lock); if (ret < 0) kfree(pmsg); } error: - mutex_unlock(&ret_lock); if (ret >= 0) wake_up_interruptible_all(&ret_queue); diff --git a/include/uapi/linux/imx_vpu.h b/include/uapi/linux/imx_vpu.h index d8f91f47b925..7c504b9dcec8 100755 --- a/include/uapi/linux/imx_vpu.h +++ b/include/uapi/linux/imx_vpu.h @@ -27,6 +27,7 @@ #define V4L2_CID_IPCM_COUNT (V4L2_CID_USER_IMX_BASE + 4) #define V4L2_CID_IPCM (V4L2_CID_USER_IMX_BASE + 5) #define V4L2_CID_HDR10META (V4L2_CID_USER_IMX_BASE + 6) +#define V4L2_CID_SECUREMODE (V4L2_CID_USER_IMX_BASE + 7) #define V4L2_MAX_ROI_REGIONS 8 struct v4l2_enc_roi_param { @@ -99,10 +100,7 @@ enum { #define V4L2_PIX_FMT_TILEX v4l2_fourcc('D', 'T', 'R', 'X') /* 10 bit tile output, uncompressed */ #define V4L2_PIX_FMT_RFC v4l2_fourcc('R', 'F', 'C', '0') /* 8bit tile output, with rfc*/ #define V4L2_PIX_FMT_RFCX v4l2_fourcc('R', 'F', 'C', 'X') /* 10 bit tile output, with rfc */ -#define V4L2_PIX_FMT_400 v4l2_fourcc('4', '0', 'S', 'P') /* YUV 400*/ #define V4L2_PIX_FMT_411SP v4l2_fourcc('4', '1', 'S', 'P') /* YUV 411 Semi planar */ -#define V4L2_PIX_FMT_422SP v4l2_fourcc('4', '2', 'S', 'P') /* YUV 422 Semi planar */ -#define V4L2_PIX_FMT_444SP v4l2_fourcc('4', '4', 'S', 'P') /* YUV 444 Semi planar */ /*codec format*/ #define V4L2_PIX_FMT_AV1 v4l2_fourcc('A', 'V', '1', '0') /* av1 */ -- 2.17.1