Commit daf3999c authored by Chen-Yu Tsai's avatar Chen-Yu Tsai Committed by Mauro Carvalho Chehab

media: hantro: Implement support for encoder commands

The V4L2 stateful encoder uAPI specification requires that drivers
support the ENCODER_CMD ioctl to allow draining of buffers. This
however was not implemented, and causes issues for some userspace
applications.

Implement support for the ENCODER_CMD ioctl using v4l2-mem2mem helpers.
This is entirely based on existing code found in the vicodec test
driver.

Fixes: 775fec69 ("media: add Rockchip VPU JPEG encoder driver")
Signed-off-by: default avatarChen-Yu Tsai <wenst@chromium.org>
Reviewed-by: default avatarEzequiel Garcia <ezequiel@vanguardiasur.com.ar>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent acd134bc
......@@ -56,6 +56,10 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts)
return hantro_get_dec_buf_addr(ctx, buf);
}
static const struct v4l2_event hantro_eos_event = {
.type = V4L2_EVENT_EOS
};
static void hantro_job_finish_no_pm(struct hantro_dev *vpu,
struct hantro_ctx *ctx,
enum vb2_buffer_state result)
......@@ -73,6 +77,12 @@ static void hantro_job_finish_no_pm(struct hantro_dev *vpu,
src->sequence = ctx->sequence_out++;
dst->sequence = ctx->sequence_cap++;
if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src)) {
dst->flags |= V4L2_BUF_FLAG_LAST;
v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event);
v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
}
v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx,
result);
}
......@@ -810,10 +820,13 @@ static int hantro_add_func(struct hantro_dev *vpu, unsigned int funcid)
snprintf(vfd->name, sizeof(vfd->name), "%s-%s", match->compatible,
funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER ? "enc" : "dec");
if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER)
if (funcid == MEDIA_ENT_F_PROC_VIDEO_ENCODER) {
vpu->encoder = func;
else
} else {
vpu->decoder = func;
v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
}
video_set_drvdata(vfd, vpu);
......
......@@ -628,6 +628,38 @@ static int vidioc_s_selection(struct file *file, void *priv,
return 0;
}
static const struct v4l2_event hantro_eos_event = {
.type = V4L2_EVENT_EOS
};
static int vidioc_encoder_cmd(struct file *file, void *priv,
struct v4l2_encoder_cmd *ec)
{
struct hantro_ctx *ctx = fh_to_ctx(priv);
int ret;
ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec);
if (ret < 0)
return ret;
if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) ||
!vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)))
return 0;
ret = v4l2_m2m_ioctl_encoder_cmd(file, priv, ec);
if (ret < 0)
return ret;
if (ec->cmd == V4L2_ENC_CMD_STOP &&
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event);
if (ec->cmd == V4L2_ENC_CMD_START)
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
return 0;
}
const struct v4l2_ioctl_ops hantro_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
......@@ -657,6 +689,9 @@ const struct v4l2_ioctl_ops hantro_ioctl_ops = {
.vidioc_g_selection = vidioc_g_selection,
.vidioc_s_selection = vidioc_s_selection,
.vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
.vidioc_encoder_cmd = vidioc_encoder_cmd,
};
static int
......@@ -744,6 +779,22 @@ static void hantro_buf_queue(struct vb2_buffer *vb)
struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
vb2_is_streaming(vb->vb2_queue) &&
v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
unsigned int i;
for (i = 0; i < vb->num_planes; i++)
vb2_set_plane_payload(vb, i, 0);
vbuf->field = V4L2_FIELD_NONE;
vbuf->sequence = ctx->sequence_cap++;
v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event);
return;
}
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
}
......@@ -759,6 +810,8 @@ static int hantro_start_streaming(struct vb2_queue *q, unsigned int count)
struct hantro_ctx *ctx = vb2_get_drv_priv(q);
int ret = 0;
v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
if (V4L2_TYPE_IS_OUTPUT(q->type))
ctx->sequence_out = 0;
else
......@@ -831,6 +884,12 @@ static void hantro_stop_streaming(struct vb2_queue *q)
hantro_return_bufs(q, v4l2_m2m_src_buf_remove);
else
hantro_return_bufs(q, v4l2_m2m_dst_buf_remove);
v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
if (V4L2_TYPE_IS_OUTPUT(q->type) &&
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event);
}
static void hantro_buf_request_complete(struct vb2_buffer *vb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment