From: Hans Verkuil <hverkuil-cisco@xxxxxxxxx> 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-cisco@xxxxxxxxx> --- 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