media: vicodec: use v4l2-mem2mem draining, stopped and next-buf-is-last states handling
Use the previously introduced v4l2-mem2mem core APIs to handle the drainig, stopped and next-buf-is-last states. With these changes, the v4l2-compliance still passes with the following commands : >>>><><><><><><><><><><><><><><><><>< 15.53 fps 15.53 fps ><><><><><><><><><><><><>< 13.99 fps 13.99 fps ><><><><><><><><><><><>< 13.52 fps 13.52 fps ><><><><><><><><><><><><>< 13.41 fps 13.41 fps ><><><><><><><><><><><><>< 13.21 fps 13.21 fps ><><><><><><><><><><><>< 13.09 fps 13.09 fps ><><><><><><>< STOP ENCODER <<< EOS EVENT v4l2-compliance SHA: 7ead0e1856b89f2e19369af452bb03fd0cd16793, 64 bits [...] Total for vicodec device /dev/video0: 50, Succeeded: 50, Failed: 0, Warnings: 0 The full output is available at [1] v4l2-compliance SHA: 7ead0e1856b89f2e19369af452bb03fd0cd16793, 64 bits [...] Total for vicodec device /dev/video1: 50, Succeeded: 50, Failed: 0, Warnings: 0 The full output is available at [2] No functional changes should be noticed. [1] https://termbin.com/25nn [2] https://termbin.com/dza4 Suggested-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Suggested-by: Maxime Jourdan <mjourdan@baylibre.com> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
parent
2b48e11386
commit
d4d137de5f
|
@ -117,15 +117,10 @@ struct vicodec_ctx {
|
||||||
struct vicodec_dev *dev;
|
struct vicodec_dev *dev;
|
||||||
bool is_enc;
|
bool is_enc;
|
||||||
bool is_stateless;
|
bool is_stateless;
|
||||||
bool is_draining;
|
|
||||||
bool next_is_last;
|
|
||||||
bool has_stopped;
|
|
||||||
spinlock_t *lock;
|
spinlock_t *lock;
|
||||||
|
|
||||||
struct v4l2_ctrl_handler hdl;
|
struct v4l2_ctrl_handler hdl;
|
||||||
|
|
||||||
struct vb2_v4l2_buffer *last_src_buf;
|
|
||||||
|
|
||||||
/* Source and destination queue data */
|
/* Source and destination queue data */
|
||||||
struct vicodec_q_data q_data[2];
|
struct vicodec_q_data q_data[2];
|
||||||
struct v4l2_fwht_state state;
|
struct v4l2_fwht_state state;
|
||||||
|
@ -431,11 +426,11 @@ static void device_run(void *priv)
|
||||||
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
|
v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false);
|
||||||
|
|
||||||
spin_lock(ctx->lock);
|
spin_lock(ctx->lock);
|
||||||
if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) {
|
if (!ctx->comp_has_next_frame &&
|
||||||
|
v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) {
|
||||||
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
||||||
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||||
ctx->is_draining = false;
|
v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx);
|
||||||
ctx->has_stopped = true;
|
|
||||||
}
|
}
|
||||||
if (ctx->is_enc || ctx->is_stateless) {
|
if (ctx->is_enc || ctx->is_stateless) {
|
||||||
src_buf->sequence = q_src->sequence++;
|
src_buf->sequence = q_src->sequence++;
|
||||||
|
@ -586,8 +581,6 @@ static int job_ready(void *priv)
|
||||||
unsigned int max_to_copy;
|
unsigned int max_to_copy;
|
||||||
unsigned int comp_frame_size;
|
unsigned int comp_frame_size;
|
||||||
|
|
||||||
if (ctx->has_stopped)
|
|
||||||
return 0;
|
|
||||||
if (ctx->source_changed)
|
if (ctx->source_changed)
|
||||||
return 0;
|
return 0;
|
||||||
if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
|
if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame)
|
||||||
|
@ -607,7 +600,8 @@ restart:
|
||||||
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
||||||
state = get_next_header(ctx, &p, p_src + sz - p);
|
state = get_next_header(ctx, &p, p_src + sz - p);
|
||||||
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) {
|
||||||
if (ctx->is_draining && src_buf == ctx->last_src_buf)
|
if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
|
||||||
|
src_buf))
|
||||||
return 1;
|
return 1;
|
||||||
job_remove_src_buf(ctx, state);
|
job_remove_src_buf(ctx, state);
|
||||||
goto restart;
|
goto restart;
|
||||||
|
@ -636,7 +630,8 @@ restart:
|
||||||
p += copy;
|
p += copy;
|
||||||
ctx->comp_size += copy;
|
ctx->comp_size += copy;
|
||||||
if (ctx->comp_size < max_to_copy) {
|
if (ctx->comp_size < max_to_copy) {
|
||||||
if (ctx->is_draining && src_buf == ctx->last_src_buf)
|
if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx,
|
||||||
|
src_buf))
|
||||||
return 1;
|
return 1;
|
||||||
job_remove_src_buf(ctx, state);
|
job_remove_src_buf(ctx, state);
|
||||||
goto restart;
|
goto restart;
|
||||||
|
@ -1219,41 +1214,6 @@ static int vidioc_s_selection(struct file *file, void *priv,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vicodec_mark_last_buf(struct vicodec_ctx *ctx)
|
|
||||||
{
|
|
||||||
struct vb2_v4l2_buffer *next_dst_buf;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
spin_lock(ctx->lock);
|
|
||||||
if (ctx->is_draining) {
|
|
||||||
ret = -EBUSY;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
if (ctx->has_stopped)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx);
|
|
||||||
ctx->is_draining = true;
|
|
||||||
if (ctx->last_src_buf)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
|
|
||||||
if (!next_dst_buf) {
|
|
||||||
ctx->next_is_last = true;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
|
||||||
vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
|
|
||||||
ctx->is_draining = false;
|
|
||||||
ctx->has_stopped = true;
|
|
||||||
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
spin_unlock(ctx->lock);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int vicodec_encoder_cmd(struct file *file, void *fh,
|
static int vicodec_encoder_cmd(struct file *file, void *fh,
|
||||||
struct v4l2_encoder_cmd *ec)
|
struct v4l2_encoder_cmd *ec)
|
||||||
{
|
{
|
||||||
|
@ -1268,18 +1228,19 @@ static int vicodec_encoder_cmd(struct file *file, void *fh,
|
||||||
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (ec->cmd == V4L2_ENC_CMD_STOP)
|
ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec);
|
||||||
return vicodec_mark_last_buf(ctx);
|
if (ret < 0)
|
||||||
ret = 0;
|
return ret;
|
||||||
spin_lock(ctx->lock);
|
|
||||||
if (ctx->is_draining) {
|
if (ec->cmd == V4L2_ENC_CMD_STOP &&
|
||||||
ret = -EBUSY;
|
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||||
} else if (ctx->has_stopped) {
|
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||||
ctx->has_stopped = false;
|
|
||||||
|
if (ec->cmd == V4L2_ENC_CMD_START &&
|
||||||
|
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||||
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
||||||
}
|
|
||||||
spin_unlock(ctx->lock);
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vicodec_decoder_cmd(struct file *file, void *fh,
|
static int vicodec_decoder_cmd(struct file *file, void *fh,
|
||||||
|
@ -1296,18 +1257,19 @@ static int vicodec_decoder_cmd(struct file *file, void *fh,
|
||||||
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
!vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dc->cmd == V4L2_DEC_CMD_STOP)
|
ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc);
|
||||||
return vicodec_mark_last_buf(ctx);
|
if (ret < 0)
|
||||||
ret = 0;
|
return ret;
|
||||||
spin_lock(ctx->lock);
|
|
||||||
if (ctx->is_draining) {
|
if (dc->cmd == V4L2_DEC_CMD_STOP &&
|
||||||
ret = -EBUSY;
|
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||||
} else if (ctx->has_stopped) {
|
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||||
ctx->has_stopped = false;
|
|
||||||
|
if (dc->cmd == V4L2_DEC_CMD_START &&
|
||||||
|
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||||
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q);
|
||||||
}
|
|
||||||
spin_unlock(ctx->lock);
|
return 0;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vicodec_enum_framesizes(struct file *file, void *fh,
|
static int vicodec_enum_framesizes(struct file *file, void *fh,
|
||||||
|
@ -1480,23 +1442,21 @@ static void vicodec_buf_queue(struct vb2_buffer *vb)
|
||||||
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
|
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (vb2_is_streaming(vq_cap)) {
|
if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
|
||||||
if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) &&
|
vb2_is_streaming(vb->vb2_queue) &&
|
||||||
ctx->next_is_last) {
|
v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < vb->num_planes; i++)
|
for (i = 0; i < vb->num_planes; i++)
|
||||||
vb->planes[i].bytesused = 0;
|
vb->planes[i].bytesused = 0;
|
||||||
vbuf->flags = V4L2_BUF_FLAG_LAST;
|
|
||||||
vbuf->field = V4L2_FIELD_NONE;
|
vbuf->field = V4L2_FIELD_NONE;
|
||||||
vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++;
|
vbuf->sequence =
|
||||||
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
|
get_q_data(ctx, vb->vb2_queue->type)->sequence++;
|
||||||
ctx->is_draining = false;
|
|
||||||
ctx->has_stopped = true;
|
v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
|
||||||
ctx->next_is_last = false;
|
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||||
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* buf_queue handles only the first source change event */
|
/* buf_queue handles only the first source change event */
|
||||||
|
@ -1609,8 +1569,7 @@ static int vicodec_start_streaming(struct vb2_queue *q,
|
||||||
chroma_div = info->width_div * info->height_div;
|
chroma_div = info->width_div * info->height_div;
|
||||||
q_data->sequence = 0;
|
q_data->sequence = 0;
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_OUTPUT(q->type))
|
v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
|
||||||
ctx->last_src_buf = NULL;
|
|
||||||
|
|
||||||
state->gop_cnt = 0;
|
state->gop_cnt = 0;
|
||||||
|
|
||||||
|
@ -1689,29 +1648,12 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
|
||||||
|
|
||||||
vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
|
vicodec_return_bufs(q, VB2_BUF_STATE_ERROR);
|
||||||
|
|
||||||
if (V4L2_TYPE_IS_OUTPUT(q->type)) {
|
v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q);
|
||||||
if (ctx->is_draining) {
|
|
||||||
struct vb2_v4l2_buffer *next_dst_buf;
|
if (V4L2_TYPE_IS_OUTPUT(q->type) &&
|
||||||
|
v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
|
||||||
|
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
||||||
|
|
||||||
spin_lock(ctx->lock);
|
|
||||||
ctx->last_src_buf = NULL;
|
|
||||||
next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
|
|
||||||
if (!next_dst_buf) {
|
|
||||||
ctx->next_is_last = true;
|
|
||||||
} else {
|
|
||||||
next_dst_buf->flags |= V4L2_BUF_FLAG_LAST;
|
|
||||||
vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE);
|
|
||||||
ctx->is_draining = false;
|
|
||||||
ctx->has_stopped = true;
|
|
||||||
v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event);
|
|
||||||
}
|
|
||||||
spin_unlock(ctx->lock);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx->is_draining = false;
|
|
||||||
ctx->has_stopped = false;
|
|
||||||
ctx->next_is_last = false;
|
|
||||||
}
|
|
||||||
if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
|
if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type))
|
||||||
ctx->first_source_change_sent = false;
|
ctx->first_source_change_sent = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue