On 10/18/2018 06:08 PM, Ezequiel Garcia wrote: > Set up a statically-allocated, dummy buffer to > be used as flush buffer, which signals > a encoding (or decoding) stop. > > When the flush buffer is queued to the OUTPUT queue, > the driver will send an V4L2_EVENT_EOS event, and > mark the CAPTURE buffer with V4L2_BUF_FLAG_LAST. I'm confused. What is the current driver doing wrong? It is already setting the LAST flag AFAIK. I don't see why a dummy buffer is needed. Regards, Hans > > With this change, it's possible to run a pipeline to completion: > > gst-launch-1.0 videotestsrc num-buffers=10 ! v4l2fwhtenc ! v4l2fwhtdec ! fakevideosink > > Signed-off-by: Ezequiel Garcia <ezequiel@xxxxxxxxxxxxx> > --- > drivers/media/platform/vicodec/vicodec-core.c | 80 ++++++++++--------- > 1 file changed, 44 insertions(+), 36 deletions(-) > > diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c > index a2c487b4b80d..4ed4dae10e30 100644 > --- a/drivers/media/platform/vicodec/vicodec-core.c > +++ b/drivers/media/platform/vicodec/vicodec-core.c > @@ -113,7 +113,7 @@ struct vicodec_ctx { > struct v4l2_ctrl_handler hdl; > > struct vb2_v4l2_buffer *last_src_buf; > - struct vb2_v4l2_buffer *last_dst_buf; > + struct vb2_v4l2_buffer flush_buf; > > /* Source and destination queue data */ > struct vicodec_q_data q_data[2]; > @@ -220,6 +220,7 @@ static void device_run(void *priv) > struct vicodec_dev *dev = ctx->dev; > struct vb2_v4l2_buffer *src_buf, *dst_buf; > struct vicodec_q_data *q_out; > + bool flushing; > u32 state; > > src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); > @@ -227,26 +228,36 @@ static void device_run(void *priv) > q_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); > > state = VB2_BUF_STATE_DONE; > - if (device_process(ctx, src_buf, dst_buf)) > + > + flushing = (src_buf == &ctx->flush_buf); > + if (!flushing && device_process(ctx, src_buf, dst_buf)) > state = VB2_BUF_STATE_ERROR; > - ctx->last_dst_buf = dst_buf; > > spin_lock(ctx->lock); > - if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) { > + if (!flushing) { > + if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) { > + dst_buf->flags |= V4L2_BUF_FLAG_LAST; > + v4l2_event_queue_fh(&ctx->fh, &eos_event); > + } > + > + if (ctx->is_enc) { > + src_buf->sequence = q_out->sequence++; > + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > + v4l2_m2m_buf_done(src_buf, state); > + } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) > + == ctx->cur_buf_offset) { > + src_buf->sequence = q_out->sequence++; > + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > + v4l2_m2m_buf_done(src_buf, state); > + ctx->cur_buf_offset = 0; > + ctx->comp_has_next_frame = false; > + } > + } else { > + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); > dst_buf->flags |= V4L2_BUF_FLAG_LAST; > v4l2_event_queue_fh(&ctx->fh, &eos_event); > } > - if (ctx->is_enc) { > - src_buf->sequence = q_out->sequence++; > - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > - v4l2_m2m_buf_done(src_buf, state); > - } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) { > - src_buf->sequence = q_out->sequence++; > - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > - v4l2_m2m_buf_done(src_buf, state); > - ctx->cur_buf_offset = 0; > - ctx->comp_has_next_frame = false; > - } > v4l2_m2m_buf_done(dst_buf, state); > ctx->comp_size = 0; > ctx->comp_magic_cnt = 0; > @@ -293,6 +304,8 @@ static int job_ready(void *priv) > src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); > if (!src_buf) > return 0; > + if (src_buf == &ctx->flush_buf) > + return 1; > p_out = vb2_plane_vaddr(&src_buf->vb2_buf, 0); > sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0); > p = p_out + ctx->cur_buf_offset; > @@ -770,21 +783,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, > return ret; > } > > -static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) > -{ > - static const struct v4l2_event eos_event = { > - .type = V4L2_EVENT_EOS > - }; > - > - spin_lock(ctx->lock); > - ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); > - if (!ctx->last_src_buf && ctx->last_dst_buf) { > - ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST; > - v4l2_event_queue_fh(&ctx->fh, &eos_event); > - } > - spin_unlock(ctx->lock); > -} > - > static int vicodec_try_encoder_cmd(struct file *file, void *fh, > struct v4l2_encoder_cmd *ec) > { > @@ -806,8 +804,8 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, > ret = vicodec_try_encoder_cmd(file, fh, ec); > if (ret < 0) > return ret; > - > - vicodec_mark_last_buf(ctx); > + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, &ctx->flush_buf); > + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); > return 0; > } > > @@ -835,8 +833,8 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, > ret = vicodec_try_decoder_cmd(file, fh, dc); > if (ret < 0) > return ret; > - > - vicodec_mark_last_buf(ctx); > + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, &ctx->flush_buf); > + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); > return 0; > } > > @@ -991,7 +989,7 @@ static void vicodec_return_bufs(struct vb2_queue *q, u32 state) > vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); > else > vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); > - if (vbuf == NULL) > + if (!vbuf || vbuf == &ctx->flush_buf) > return; > spin_lock(ctx->lock); > v4l2_m2m_buf_done(vbuf, state); > @@ -1031,7 +1029,6 @@ static int vicodec_start_streaming(struct vb2_queue *q, > state->ref_frame.cb = state->ref_frame.luma + size; > state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; > ctx->last_src_buf = NULL; > - ctx->last_dst_buf = NULL; > state->gop_cnt = 0; > ctx->cur_buf_offset = 0; > ctx->comp_size = 0; > @@ -1158,6 +1155,7 @@ static int vicodec_open(struct file *file) > struct vicodec_dev *dev = video_drvdata(file); > struct vicodec_ctx *ctx = NULL; > struct v4l2_ctrl_handler *hdl; > + struct vb2_queue *vq; > unsigned int size; > int rc = 0; > > @@ -1234,6 +1232,16 @@ static int vicodec_open(struct file *file) > > v4l2_fh_add(&ctx->fh); > > + /* Setup a dummy flush buffer, used to signal > + * encoding/decoding stop operation. When this buffer > + * is queued to the OUTPUT queue, the driver will send > + * V4L2_EVENT_EOS and send the last buffer to userspace. > + */ > + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, multiplanar ? > + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : > + V4L2_BUF_TYPE_VIDEO_OUTPUT); > + ctx->flush_buf.vb2_buf.vb2_queue = vq; > + > open_unlock: > mutex_unlock(vfd->lock); > return rc; >