Skip to content

Commit

Permalink
media: imx-jpeg: Support dynamic resolution change
Browse files Browse the repository at this point in the history
[ Upstream commit b4e1fb8 ]

To support dynamic resolution change,
driver should meet the following conditions:
1. the previous pictures are all decoded before source change event.
2. prevent decoding new resolution pictures with incorrect capture
   buffer, until user handle source change event and setup capture.
3. report correct fmt and resolution during source change.

Signed-off-by: Ming Qian <ming.qian@nxp.com>
Reviewed-by: Mirela Rabulea <mirela.rabulea@nxp.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
mingqian-0 authored and gregkh committed Aug 17, 2022
1 parent 07888b8 commit 88355f7
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 16 deletions.
69 changes: 53 additions & 16 deletions drivers/media/platform/imx-jpeg/mxc-jpeg.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,13 +919,14 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
{
struct device *dev = ctx->mxc_jpeg->dev;
struct mxc_jpeg_q_data *q_data_cap;
bool src_chg = false;

if (!jpeg_src_buf->fmt)
return src_chg;
return false;

q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (q_data_cap->w != jpeg_src_buf->w || q_data_cap->h != jpeg_src_buf->h) {
if (q_data_cap->fmt != jpeg_src_buf->fmt ||
q_data_cap->w != jpeg_src_buf->w ||
q_data_cap->h != jpeg_src_buf->h) {
dev_dbg(dev, "Detected jpeg res=(%dx%d)->(%dx%d), pixfmt=%c%c%c%c\n",
q_data_cap->w, q_data_cap->h,
jpeg_src_buf->w, jpeg_src_buf->h,
Expand Down Expand Up @@ -962,9 +963,16 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx,
mxc_jpeg_bytesperline(q_data_cap, jpeg_src_buf->fmt->precision);
mxc_jpeg_sizeimage(q_data_cap);
notify_src_chg(ctx);
src_chg = true;
ctx->source_change = 1;
}
return src_chg;
return ctx->source_change ? true : false;
}

static int mxc_jpeg_job_ready(void *priv)
{
struct mxc_jpeg_ctx *ctx = priv;

return ctx->source_change ? 0 : 1;
}

static void mxc_jpeg_device_run(void *priv)
Expand Down Expand Up @@ -1014,6 +1022,13 @@ static void mxc_jpeg_device_run(void *priv)

return;
}
if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE) {
if (ctx->source_change || mxc_jpeg_source_change(ctx, jpeg_src_buf)) {
spin_unlock_irqrestore(&ctx->mxc_jpeg->hw_lock, flags);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
return;
}
}

/*
* TODO: this reset should be removed, once we figure out
Expand Down Expand Up @@ -1065,6 +1080,7 @@ static void mxc_jpeg_set_last_buffer_dequeued(struct mxc_jpeg_ctx *ctx)
q->last_buffer_dequeued = true;
wake_up(&q->done_wq);
ctx->stopped = 0;
ctx->header_parsed = false;
}

static int mxc_jpeg_decoder_cmd(struct file *file, void *priv,
Expand Down Expand Up @@ -1158,6 +1174,8 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, q->type);
int ret;

if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(q->type))
ctx->source_change = 0;
dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
q_data->sequence = 0;

Expand Down Expand Up @@ -1336,16 +1354,15 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
dev_warn(dev, "Invalid user resolution 0x0");
dev_warn(dev, "Keeping resolution from JPEG: %dx%d",
header.frame.width, header.frame.height);
q_data_out->w = header.frame.width;
q_data_out->h = header.frame.height;
} else if (header.frame.width != q_data_out->w ||
header.frame.height != q_data_out->h) {
dev_err(dev,
"Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
header.frame.width, header.frame.height,
q_data_out->w, q_data_out->h);
return -EINVAL;
}
q_data_out->w = header.frame.width;
q_data_out->h = header.frame.height;
if (header.frame.width % 8 != 0 || header.frame.height % 8 != 0) {
dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
header.frame.width, header.frame.height);
Expand Down Expand Up @@ -1381,8 +1398,10 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
jpeg_src_buf->fmt = mxc_jpeg_find_format(ctx, fourcc);
jpeg_src_buf->w = header.frame.width;
jpeg_src_buf->h = header.frame.height;
ctx->header_parsed = true;

mxc_jpeg_source_change(ctx, jpeg_src_buf);
if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx))
mxc_jpeg_source_change(ctx, jpeg_src_buf);

return 0;
}
Expand Down Expand Up @@ -1459,6 +1478,7 @@ static void mxc_jpeg_buf_finish(struct vb2_buffer *vb)
if (list_empty(&q->done_list)) {
vbuf->flags |= V4L2_BUF_FLAG_LAST;
ctx->stopped = 0;
ctx->header_parsed = false;
}
}

Expand Down Expand Up @@ -1604,26 +1624,42 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
struct mxc_jpeg_q_data *q_data = mxc_jpeg_get_q_data(ctx, f->type);

if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE)
if (ctx->mxc_jpeg->mode == MXC_JPEG_ENCODE) {
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_ENC);
else
} else if (!ctx->header_parsed) {
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_RAW);
} else {
/* For the decoder CAPTURE queue, only enumerate the raw formats
* supported for the format currently active on OUTPUT
* (more precisely what was propagated on capture queue
* after jpeg parse on the output buffer)
*/
if (f->index)
return -EINVAL;
f->pixelformat = q_data->fmt->fourcc;
strscpy(f->description, q_data->fmt->name, sizeof(f->description));
return 0;
}
}

static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
u32 type = ctx->mxc_jpeg->mode == MXC_JPEG_DECODE ? MXC_JPEG_FMT_TYPE_ENC :
MXC_JPEG_FMT_TYPE_RAW;
int ret;

ret = enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f, type);
if (ret)
return ret;
if (ctx->mxc_jpeg->mode == MXC_JPEG_DECODE)
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_ENC);
else
return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
MXC_JPEG_FMT_TYPE_RAW);
f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION;
return 0;
}

static int mxc_jpeg_try_fmt(struct v4l2_format *f, const struct mxc_jpeg_fmt *fmt,
Expand Down Expand Up @@ -1981,6 +2017,7 @@ static const struct v4l2_file_operations mxc_jpeg_fops = {
};

static const struct v4l2_m2m_ops mxc_jpeg_m2m_ops = {
.job_ready = mxc_jpeg_job_ready,
.device_run = mxc_jpeg_device_run,
};

Expand Down
2 changes: 2 additions & 0 deletions drivers/media/platform/imx-jpeg/mxc-jpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ struct mxc_jpeg_ctx {
unsigned int stopping;
unsigned int stopped;
unsigned int slot;
unsigned int source_change;
bool header_parsed;
};

struct mxc_jpeg_slot_data {
Expand Down

0 comments on commit 88355f7

Please sign in to comment.