From: Hans Verkuil <hverkuil-ci...@xs4all.nl>

With the new mem2mem functionality it is now easy to write the
result of the encoder to multiple buffers.

Signed-off-by: Hans Verkuil <hverkuil-ci...@xs4all.nl>
---
 drivers/media/platform/vicodec/vicodec-core.c | 91 +++++++++++++++----
 1 file changed, 75 insertions(+), 16 deletions(-)

diff --git a/drivers/media/platform/vicodec/vicodec-core.c 
b/drivers/media/platform/vicodec/vicodec-core.c
index 2b7daff63425..f422804ab40e 100644
--- a/drivers/media/platform/vicodec/vicodec-core.c
+++ b/drivers/media/platform/vicodec/vicodec-core.c
@@ -115,6 +115,11 @@ struct vicodec_ctx {
        struct vb2_v4l2_buffer *last_src_buf;
        struct vb2_v4l2_buffer *last_dst_buf;
 
+       u64                     dst_timestamp;
+       u32                     dst_field;
+       u32                     dst_flags;
+       struct v4l2_timecode    dst_timecode;
+
        /* Source and destination queue data */
        struct vicodec_q_data   q_data[2];
        struct v4l2_fwht_state  state;
@@ -161,11 +166,13 @@ static int device_process(struct vicodec_ctx *ctx,
        int ret;
 
        q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
-       if (ctx->is_enc)
+       if (ctx->is_enc) {
                p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0);
-       else
+               p_dst = state->compressed_frame;
+       } else {
                p_src = state->compressed_frame;
-       p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
+               p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0);
+       }
        if (!p_src || !p_dst) {
                v4l2_err(&dev->v4l2_dev,
                         "Acquiring kernel pointers to buffers failed\n");
@@ -180,7 +187,11 @@ static int device_process(struct vicodec_ctx *ctx,
                ret = v4l2_fwht_encode(state, p_src, p_dst);
                if (ret < 0)
                        return ret;
+               ctx->comp_size = ret;
+               ret = min_t(u32, ret, vb2_plane_size(&dst_vb->vb2_buf, 0));
+               ctx->cur_buf_offset = ret;
                vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
+               memcpy(vb2_plane_vaddr(&dst_vb->vb2_buf, 0), p_dst, ret);
        } else {
                state->info = q_dst->info;
                ret = v4l2_fwht_decode(state, p_src, p_dst);
@@ -240,6 +251,14 @@ static void device_run(void *priv)
                src_buf->sequence = q_src->sequence++;
                src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
                v4l2_m2m_buf_done(src_buf, state);
+               if (ctx->cur_buf_offset < ctx->comp_size) {
+                       ctx->dst_timestamp = dst_buf->vb2_buf.timestamp;
+                       ctx->dst_field = dst_buf->field;
+                       ctx->dst_flags = dst_buf->flags;
+                       dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
+                       if (dst_buf->flags & V4L2_BUF_FLAG_TIMECODE)
+                               ctx->dst_timecode = dst_buf->timecode;
+               }
        } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 
ctx->cur_buf_offset) {
                src_buf->sequence = q_src->sequence++;
                src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
@@ -247,16 +266,22 @@ static void device_run(void *priv)
                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;
-       ctx->comp_has_frame = false;
+       if (!ctx->is_enc) {
+               ctx->comp_size = 0;
+               ctx->comp_magic_cnt = 0;
+               ctx->comp_has_frame = false;
+       }
        spin_unlock(ctx->lock);
 
-       if (ctx->is_enc)
-               v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
-       else
+       if (ctx->is_enc) {
+               if (ctx->cur_buf_offset < ctx->comp_size)
+                       v4l2_m2m_job_writing(dev->enc_dev, ctx->fh.m2m_ctx);
+               else
+                       v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx);
+       } else {
                v4l2_m2m_job_finish(dev->dec_dev, ctx->fh.m2m_ctx);
+       }
+       v4l2_m2m_buf_done(dst_buf, state);
 }
 
 static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state)
@@ -273,6 +298,41 @@ static void job_remove_src_buf(struct vicodec_ctx *ctx, 
u32 state)
        spin_unlock(ctx->lock);
 }
 
+static void job_write(void *priv)
+{
+       struct vicodec_ctx *ctx = priv;
+       struct v4l2_fwht_state *state = &ctx->state;
+       struct vb2_v4l2_buffer *dst_buf;
+       struct vicodec_q_data *q_cap;
+       u32 size;
+
+       q_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       while (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) &&
+              ctx->cur_buf_offset < ctx->comp_size) {
+               dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+               size = min_t(u32, ctx->comp_size - ctx->cur_buf_offset,
+                            vb2_plane_size(&dst_buf->vb2_buf, 0));
+               vb2_set_plane_payload(&dst_buf->vb2_buf, 0, size);
+               memcpy(vb2_plane_vaddr(&dst_buf->vb2_buf, 0),
+                      state->compressed_frame + ctx->cur_buf_offset, size);
+               ctx->cur_buf_offset += size;
+
+               dst_buf->sequence = q_cap->sequence++;
+               dst_buf->vb2_buf.timestamp = ctx->dst_timestamp;
+               if (ctx->dst_flags & V4L2_BUF_FLAG_TIMECODE)
+                       dst_buf->timecode = ctx->dst_timecode;
+               dst_buf->field = ctx->dst_field;
+               dst_buf->flags = ctx->dst_flags;
+
+               if (ctx->cur_buf_offset < ctx->comp_size)
+                       dst_buf->flags &= ~V4L2_BUF_FLAG_LAST;
+
+               if (ctx->cur_buf_offset == ctx->comp_size)
+                       v4l2_m2m_job_finish(ctx->dev->enc_dev, ctx->fh.m2m_ctx);
+               v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+       }
+}
+
 static int job_ready(void *priv)
 {
        static const u8 magic[] = {
@@ -536,7 +596,7 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct 
v4l2_format *f)
                pix->sizeimage = pix->width * pix->height *
                        info->sizeimage_mult / info->sizeimage_div;
                if (pix->pixelformat == V4L2_PIX_FMT_FWHT)
-                       pix->sizeimage += sizeof(struct fwht_cframe_hdr);
+                       pix->sizeimage /= 16;
                break;
        case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
        case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
@@ -554,7 +614,7 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct 
v4l2_format *f)
                plane->sizeimage = pix_mp->width * pix_mp->height *
                        info->sizeimage_mult / info->sizeimage_div;
                if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT)
-                       plane->sizeimage += sizeof(struct fwht_cframe_hdr);
+                       plane->sizeimage /= 16;
                memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
                memset(plane->reserved, 0, sizeof(plane->reserved));
                break;
@@ -1204,16 +1264,14 @@ static int vicodec_open(struct file *file)
        if (ctx->is_enc)
                ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
        else
-               ctx->q_data[V4L2_M2M_SRC].sizeimage =
-                       size + sizeof(struct fwht_cframe_hdr);
+               ctx->q_data[V4L2_M2M_SRC].sizeimage = size / 16;
        ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
        ctx->q_data[V4L2_M2M_DST].info =
                ctx->is_enc ? &pixfmt_fwht : v4l2_fwht_get_pixfmt(0);
        size = 1280 * 720 * ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult /
                ctx->q_data[V4L2_M2M_DST].info->sizeimage_div;
        if (ctx->is_enc)
-               ctx->q_data[V4L2_M2M_DST].sizeimage =
-                       size + sizeof(struct fwht_cframe_hdr);
+               ctx->q_data[V4L2_M2M_DST].sizeimage = size / 16;
        else
                ctx->q_data[V4L2_M2M_DST].sizeimage = size;
        ctx->state.colorspace = V4L2_COLORSPACE_REC709;
@@ -1281,6 +1339,7 @@ static const struct video_device vicodec_videodev = {
 static const struct v4l2_m2m_ops m2m_ops = {
        .device_run     = device_run,
        .job_ready      = job_ready,
+       .job_write      = job_write,
 };
 
 static int vicodec_probe(struct platform_device *pdev)
-- 
2.19.2

Reply via email to