All of lore.kernel.org
 help / color / mirror / Atom feed
From: Hugues Fruchet <hugues.fruchet@st.com>
To: <linux-media@vger.kernel.org>, Hans Verkuil <hverkuil@xs4all.nl>
Cc: <kernel@stlinux.com>,
	Benjamin Gaignard <benjamin.gaignard@linaro.org>,
	Hugues Fruchet <hugues.fruchet@st.com>,
	Jean-Christophe Trotin <jean-christophe.trotin@st.com>
Subject: [PATCH v7 08/10] [media] st-delta: EOS (End Of Stream) support
Date: Thu, 2 Feb 2017 15:59:51 +0100	[thread overview]
Message-ID: <1486047593-18581-9-git-send-email-hugues.fruchet@st.com> (raw)
In-Reply-To: <1486047593-18581-1-git-send-email-hugues.fruchet@st.com>

EOS (End Of Stream) support allows user to get
all the potential decoded frames remaining in decoder
pipeline after having reached the end of video bitstream.
To do so, user calls VIDIOC_DECODER_CMD(V4L2_DEC_CMD_STOP)
which will drain the decoder and get the drained frames
that are then returned to user.
User is informed of EOS completion in two ways:
 - dequeue of an empty frame flagged to V4L2_BUF_FLAG_LAST
 - reception of a V4L2_EVENT_EOS event.
If, unfortunately, no buffer is available on CAPTURE queue
to return the empty frame, EOS is delayed till user queue
one CAPTURE buffer.

Acked-by: Peter Griffin <peter.griffin@linaro.org>
Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
---
 drivers/media/platform/sti/delta/delta-v4l2.c | 146 +++++++++++++++++++++++++-
 drivers/media/platform/sti/delta/delta.h      |  23 ++++
 2 files changed, 168 insertions(+), 1 deletion(-)

diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
index 237a938..c959614 100644
--- a/drivers/media/platform/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -106,7 +106,8 @@ static void delta_frame_done(struct delta_ctx *ctx, struct delta_frame *frame,
 	vbuf->sequence = ctx->frame_num++;
 	v4l2_m2m_buf_done(vbuf, err ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
 
-	ctx->output_frames++;
+	if (frame->info.size) /* ignore EOS */
+		ctx->output_frames++;
 }
 
 static void requeue_free_frames(struct delta_ctx *ctx)
@@ -762,6 +763,135 @@ static int delta_g_selection(struct file *file, void *fh,
 	return 0;
 }
 
+static void delta_complete_eos(struct delta_ctx *ctx,
+			       struct delta_frame *frame)
+{
+	struct delta_dev *delta = ctx->dev;
+	const struct v4l2_event ev = {.type = V4L2_EVENT_EOS};
+
+	/*
+	 * Send EOS to user:
+	 * - by returning an empty frame flagged to V4L2_BUF_FLAG_LAST
+	 * - and then send EOS event
+	 */
+
+	/* empty frame */
+	frame->info.size = 0;
+
+	/* set the last buffer flag */
+	frame->flags |= V4L2_BUF_FLAG_LAST;
+
+	/* release frame to user */
+	delta_frame_done(ctx, frame, 0);
+
+	/* send EOS event */
+	v4l2_event_queue_fh(&ctx->fh, &ev);
+
+	dev_dbg(delta->dev, "%s EOS completed\n", ctx->name);
+}
+
+static int delta_try_decoder_cmd(struct file *file, void *fh,
+				 struct v4l2_decoder_cmd *cmd)
+{
+	if (cmd->cmd != V4L2_DEC_CMD_STOP)
+		return -EINVAL;
+
+	if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK)
+		return -EINVAL;
+
+	if (!(cmd->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) &&
+	    (cmd->stop.pts != 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+static int delta_decoder_stop_cmd(struct delta_ctx *ctx, void *fh)
+{
+	const struct delta_dec *dec = ctx->dec;
+	struct delta_dev *delta = ctx->dev;
+	struct delta_frame *frame = NULL;
+	int ret = 0;
+
+	dev_dbg(delta->dev, "%s EOS received\n", ctx->name);
+
+	if (ctx->state != DELTA_STATE_READY)
+		return 0;
+
+	/* drain the decoder */
+	call_dec_op(dec, drain, ctx);
+
+	/* release to user drained frames */
+	while (1) {
+		frame = NULL;
+		ret = call_dec_op(dec, get_frame, ctx, &frame);
+		if (ret == -ENODATA) {
+			/* no more decoded frames */
+			break;
+		}
+		if (frame) {
+			dev_dbg(delta->dev, "%s drain frame[%d]\n",
+				ctx->name, frame->index);
+
+			/* pop timestamp and mark frame with it */
+			delta_pop_dts(ctx, &frame->dts);
+
+			/* release decoded frame to user */
+			delta_frame_done(ctx, frame, 0);
+		}
+	}
+
+	/* try to complete EOS */
+	ret = delta_get_free_frame(ctx, &frame);
+	if (ret)
+		goto delay_eos;
+
+	/* new frame available, EOS can now be completed */
+	delta_complete_eos(ctx, frame);
+
+	ctx->state = DELTA_STATE_EOS;
+
+	return 0;
+
+delay_eos:
+	/*
+	 * EOS completion from driver is delayed because
+	 * we don't have a free empty frame available.
+	 * EOS completion is so delayed till next frame_queue() call
+	 * to be sure to have a free empty frame available.
+	 */
+	ctx->state = DELTA_STATE_WF_EOS;
+	dev_dbg(delta->dev, "%s EOS delayed\n", ctx->name);
+
+	return 0;
+}
+
+static int delta_decoder_cmd(struct file *file, void *fh,
+			     struct v4l2_decoder_cmd *cmd)
+{
+	struct delta_ctx *ctx = to_ctx(fh);
+	int ret = 0;
+
+	ret = delta_try_decoder_cmd(file, fh, cmd);
+	if (ret)
+		return ret;
+
+	return delta_decoder_stop_cmd(ctx, fh);
+}
+
+static int delta_subscribe_event(struct v4l2_fh *fh,
+				 const struct v4l2_event_subscription *sub)
+{
+	switch (sub->type) {
+	case V4L2_EVENT_EOS:
+		return v4l2_event_subscribe(fh, sub, 2, NULL);
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 /* v4l2 ioctl ops */
 static const struct v4l2_ioctl_ops delta_ioctl_ops = {
 	.vidioc_querycap = delta_querycap,
@@ -782,6 +912,10 @@ static int delta_g_selection(struct file *file, void *fh,
 	.vidioc_streamon = v4l2_m2m_ioctl_streamon,
 	.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
 	.vidioc_g_selection = delta_g_selection,
+	.vidioc_try_decoder_cmd = delta_try_decoder_cmd,
+	.vidioc_decoder_cmd = delta_decoder_cmd,
+	.vidioc_subscribe_event = delta_subscribe_event,
+	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /*
@@ -1376,6 +1510,16 @@ static void delta_vb2_frame_queue(struct vb2_buffer *vb)
 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
 	struct delta_frame *frame = to_frame(vbuf);
 
+	if (ctx->state == DELTA_STATE_WF_EOS) {
+		/* new frame available, EOS can now be completed */
+		delta_complete_eos(ctx, frame);
+
+		ctx->state = DELTA_STATE_EOS;
+
+		/* return, no need to recycle this buffer to decoder */
+		return;
+	}
+
 	/* recycle this frame */
 	delta_recycle(ctx, frame);
 }
diff --git a/drivers/media/platform/sti/delta/delta.h b/drivers/media/platform/sti/delta/delta.h
index d4a401b..60c07324 100644
--- a/drivers/media/platform/sti/delta/delta.h
+++ b/drivers/media/platform/sti/delta/delta.h
@@ -27,11 +27,19 @@
  *@DELTA_STATE_READY:
  *	Decoding instance is ready to decode compressed access unit.
  *
+ *@DELTA_STATE_WF_EOS:
+ *	Decoding instance is waiting for EOS (End Of Stream) completion.
+ *
+ *@DELTA_STATE_EOS:
+ *	EOS (End Of Stream) is completed (signaled to user). Decoding instance
+ *	should then be closed.
  */
 enum delta_state {
 	DELTA_STATE_WF_FORMAT,
 	DELTA_STATE_WF_STREAMINFO,
 	DELTA_STATE_READY,
+	DELTA_STATE_WF_EOS,
+	DELTA_STATE_EOS
 };
 
 /*
@@ -237,6 +245,7 @@ struct delta_ipc_param {
  * @get_frame:		get the next decoded frame available, see below
  * @recycle:		recycle the given frame, see below
  * @flush:		(optional) flush decoder, see below
+ * @drain:		(optional) drain decoder, see below
  */
 struct delta_dec {
 	const char *name;
@@ -371,6 +380,18 @@ struct delta_dec {
 	 * decoding logic.
 	 */
 	int (*flush)(struct delta_ctx *ctx);
+
+	/*
+	 * drain() - drain decoder
+	 * @ctx:	(in) instance
+	 *
+	 * Optional.
+	 * Mark decoder pending frames (decoded but not yet output) as ready
+	 * so that they can be output to client at EOS (End Of Stream).
+	 * get_frame() is to be called in a loop right after drain() to
+	 * get all those pending frames.
+	 */
+	int (*drain)(struct delta_ctx *ctx);
 };
 
 struct delta_dev;
@@ -497,6 +518,8 @@ static inline char *frame_type_str(u32 flags)
 		return "P";
 	if (flags & V4L2_BUF_FLAG_BFRAME)
 		return "B";
+	if (flags & V4L2_BUF_FLAG_LAST)
+		return "EOS";
 	return "?";
 }
 
-- 
1.9.1


  parent reply	other threads:[~2017-02-02 15:00 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-02 14:59 [PATCH v7 00/10] Add support for DELTA video decoder of STMicroelectronics STiH4xx SoC series Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 01/10] Documentation: DT: add bindings for ST DELTA Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 02/10] ARM: dts: STiH407-family: add DELTA dt node Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 03/10] ARM: multi_v7_defconfig: enable STMicroelectronics DELTA Support Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 04/10] [media] MAINTAINERS: add st-delta driver Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 05/10] [media] st-delta: STiH4xx multi-format video decoder v4l2 driver Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 06/10] [media] st-delta: add memory allocator helper functions Hugues Fruchet
2017-02-02 14:59 ` [PATCH v7 07/10] [media] st-delta: rpmsg ipc support Hugues Fruchet
2017-02-02 14:59 ` Hugues Fruchet [this message]
2017-02-02 14:59 ` [PATCH v7 09/10] [media] st-delta: add mjpeg support Hugues Fruchet
2017-02-08 12:19   ` Mauro Carvalho Chehab
2017-02-08 15:40     ` Hugues FRUCHET
2017-02-02 14:59 ` [PATCH v7 10/10] [media] st-delta: debug: trace stream/frame information & summary Hugues Fruchet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1486047593-18581-9-git-send-email-hugues.fruchet@st.com \
    --to=hugues.fruchet@st.com \
    --cc=benjamin.gaignard@linaro.org \
    --cc=hverkuil@xs4all.nl \
    --cc=jean-christophe.trotin@st.com \
    --cc=kernel@stlinux.com \
    --cc=linux-media@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.