Provide a callback for codec variant drivers to indicate the correct output pixel-format after receiving the SPS of the byte-stream, on the initial s_ctrl ioctl call from user-space. Signed-off-by: Jonas Karlman <jonas@xxxxxxxxx> Signed-off-by: Sebastian Fricke <sebastian.fricke@xxxxxxxxxxxxx> --- drivers/staging/media/rkvdec/TODO | 2 ++ drivers/staging/media/rkvdec/rkvdec.c | 45 +++++++++++++++++++++++---- drivers/staging/media/rkvdec/rkvdec.h | 2 ++ 3 files changed, 43 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/rkvdec/TODO b/drivers/staging/media/rkvdec/TODO index 2c0779383276..44e1e06ee6e4 100644 --- a/drivers/staging/media/rkvdec/TODO +++ b/drivers/staging/media/rkvdec/TODO @@ -9,3 +9,5 @@ code in rkvdec_request_validate and cedrus_request_validate. The helper needs to the driver private data associated with the videobuf2 queue, from a media request. + +* Implement the valid_fmt callback for H264 and VP9 diff --git a/drivers/staging/media/rkvdec/rkvdec.c b/drivers/staging/media/rkvdec/rkvdec.c index 7bab7586918c..2625e0a736f4 100644 --- a/drivers/staging/media/rkvdec/rkvdec.c +++ b/drivers/staging/media/rkvdec/rkvdec.c @@ -27,6 +27,23 @@ #include "rkvdec.h" #include "rkvdec-regs.h" +/* + * Fetch the optimal pixel-format directly from the codec variation. If the + * valid_fmt callback is not implemented, then the context variable valid_fmt + * will be unset. + * When the `valid_fmt` variable is not set, the default pixel_format (the first + * entry of the decoded_fmts) is used and `enum_capture_fmt` will return all + * available formats for the current coded format. + */ +static int rkvdec_get_valid_fmt(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) +{ + const struct rkvdec_coded_fmt_desc *coded_desc = ctx->coded_fmt_desc; + + if (coded_desc->ops->valid_fmt) + return coded_desc->ops->valid_fmt(ctx, ctrl); + return 0; +} + static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) { struct rkvdec_ctx *ctx = container_of(ctrl->handler, struct rkvdec_ctx, ctrl_hdl); @@ -35,6 +52,9 @@ static int rkvdec_try_ctrl(struct v4l2_ctrl *ctrl) if (desc->ops->try_ctrl) return desc->ops->try_ctrl(ctx, ctrl); + if (ctx->valid_fmt && ctx->valid_fmt != rkvdec_get_valid_fmt(ctx, ctrl)) + /* Only allow the current valid format */ + return -EINVAL; return 0; } @@ -190,6 +210,7 @@ static void rkvdec_reset_decoded_fmt(struct rkvdec_ctx *ctx) { struct v4l2_format *f = &ctx->decoded_fmt; + ctx->valid_fmt = 0; rkvdec_reset_fmt(ctx, f, ctx->coded_fmt_desc->decoded_fmts[0]); f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; v4l2_fill_pixfmt_mp(&f->fmt.pix_mp, @@ -249,14 +270,17 @@ static int rkvdec_try_capture_fmt(struct file *file, void *priv, if (WARN_ON(!coded_desc)) return -EINVAL; - for (i = 0; i < coded_desc->num_decoded_fmts; i++) { - if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) - break; + if (ctx->valid_fmt) { + pix_mp->pixelformat = ctx->valid_fmt; + } else { + for (i = 0; i < coded_desc->num_decoded_fmts; i++) { + if (coded_desc->decoded_fmts[i] == pix_mp->pixelformat) + break; + } + if (i == coded_desc->num_decoded_fmts) + pix_mp->pixelformat = coded_desc->decoded_fmts[0]; } - if (i == coded_desc->num_decoded_fmts) - pix_mp->pixelformat = coded_desc->decoded_fmts[0]; - /* Always apply the frmsize constraint of the coded end. */ pix_mp->width = max(pix_mp->width, ctx->coded_fmt.fmt.pix_mp.width); pix_mp->height = max(pix_mp->height, ctx->coded_fmt.fmt.pix_mp.height); @@ -325,6 +349,7 @@ static int rkvdec_s_capture_fmt(struct file *file, void *priv, return ret; ctx->decoded_fmt = *f; + ctx->valid_fmt = f->fmt.pix_mp.pixelformat; return 0; } @@ -428,6 +453,14 @@ static int rkvdec_enum_capture_fmt(struct file *file, void *priv, if (WARN_ON(!ctx->coded_fmt_desc)) return -EINVAL; + if (ctx->valid_fmt) { + if (f->index) + return -EINVAL; + + f->pixelformat = ctx->valid_fmt; + return 0; + } + if (f->index >= ctx->coded_fmt_desc->num_decoded_fmts) return -EINVAL; diff --git a/drivers/staging/media/rkvdec/rkvdec.h b/drivers/staging/media/rkvdec/rkvdec.h index 633335ebb9c4..b9e219438bc9 100644 --- a/drivers/staging/media/rkvdec/rkvdec.h +++ b/drivers/staging/media/rkvdec/rkvdec.h @@ -66,6 +66,7 @@ vb2_to_rkvdec_decoded_buf(struct vb2_buffer *buf) struct rkvdec_coded_fmt_ops { int (*adjust_fmt)(struct rkvdec_ctx *ctx, struct v4l2_format *f); + u32 (*valid_fmt)(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl); int (*start)(struct rkvdec_ctx *ctx); void (*stop)(struct rkvdec_ctx *ctx); int (*run)(struct rkvdec_ctx *ctx); @@ -101,6 +102,7 @@ struct rkvdec_ctx { struct v4l2_fh fh; struct v4l2_format coded_fmt; struct v4l2_format decoded_fmt; + u32 valid_fmt; const struct rkvdec_coded_fmt_desc *coded_fmt_desc; struct v4l2_ctrl_handler ctrl_hdl; struct rkvdec_dev *dev; -- 2.25.1