Implement the valid format and sps validation callbacks for H264. H264 already has a SPS validation function, adjust it to fit the function the declaration and add error messages. Additionally, add a function to fetch attributes from the SPS in a human readable format to make the code more self documenting. Signed-off-by: Sebastian Fricke <sebastian.fricke@xxxxxxxxxxxxx> --- drivers/staging/media/rkvdec/rkvdec-h264.c | 105 ++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 25 deletions(-) diff --git a/drivers/staging/media/rkvdec/rkvdec-h264.c b/drivers/staging/media/rkvdec/rkvdec-h264.c index 4fc167b42cf0..17b215874ddd 100644 --- a/drivers/staging/media/rkvdec/rkvdec-h264.c +++ b/drivers/staging/media/rkvdec/rkvdec-h264.c @@ -1026,40 +1026,80 @@ static int rkvdec_h264_adjust_fmt(struct rkvdec_ctx *ctx, return 0; } -static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, - const struct v4l2_ctrl_h264_sps *sps) +/* + * Convert some fields from the SPS structure into human readable attributes. + */ +static int rkvdec_h264_get_sps_attributes(struct rkvdec_ctx *ctx, void *sps, + struct sps_attributes *attributes) +{ + struct v4l2_ctrl_h264_sps *h264_sps = sps; + unsigned int width = (h264_sps->pic_width_in_mbs_minus1 + 1) * 16; + unsigned int height = (h264_sps->pic_height_in_map_units_minus1 + 1) * 16; + /* + * When frame_mbs_only_flag is not set, this is field height, + * which is half the final height (see (7-18) in the + * specification) + */ + if (!(h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) + height *= 2; + + attributes->width = width; + attributes->height = height; + attributes->luma_bitdepth = h264_sps->bit_depth_luma_minus8 + 8; + attributes->chroma_bitdepth = h264_sps->bit_depth_chroma_minus8 + 8; + switch (h264_sps->chroma_format_idc) { + case 0: + attributes->subsampling = 400; + break; + case 1: + attributes->subsampling = 420; + break; + case 2: + attributes->subsampling = 422; + break; + case 3: + attributes->subsampling = 444; + break; + }; + return 0; +} + +static int rkvdec_h264_validate_sps(struct rkvdec_ctx *ctx, void *sps, + struct v4l2_pix_format_mplane *pix_mp) { - unsigned int width, height; + struct sps_attributes attributes = {0}; + + rkvdec_h264_get_sps_attributes(ctx, sps, &attributes); /* * TODO: The hardware supports 10-bit and 4:2:2 profiles, * but it's currently broken in the driver. * Reject them for now, until it's fixed. */ - if (sps->chroma_format_idc > 1) - /* Only 4:0:0 and 4:2:0 are supported */ + if (attributes.subsampling > 420) { + dev_err(ctx->dev->dev, + "Only 4:0:0 and 4:2:0 subsampling schemes are supported, got: %d\n", + attributes.subsampling); return -EINVAL; - if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8) - /* Luma and chroma bit depth mismatch */ + } + if (attributes.luma_bitdepth != attributes.chroma_bitdepth) { + dev_err(ctx->dev->dev, + "Luma and chroma bit depth mismatch, luma %d, chroma %d\n", + attributes.luma_bitdepth, attributes.chroma_bitdepth); return -EINVAL; - if (sps->bit_depth_luma_minus8 != 0) - /* Only 8-bit is supported */ + } + if (attributes.luma_bitdepth != 8) { + dev_err(ctx->dev->dev, "Only 8-bit H264 formats supported, SPS %d\n", + attributes.luma_bitdepth); return -EINVAL; + } - width = (sps->pic_width_in_mbs_minus1 + 1) * 16; - height = (sps->pic_height_in_map_units_minus1 + 1) * 16; - - /* - * When frame_mbs_only_flag is not set, this is field height, - * which is half the final height (see (7-18) in the - * specification) - */ - if (!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)) - height *= 2; - - if (width > ctx->coded_fmt.fmt.pix_mp.width || - height > ctx->coded_fmt.fmt.pix_mp.height) + if (attributes.width > pix_mp->width || attributes.height > pix_mp->height) { + dev_err(ctx->dev->dev, + "Incompatible SPS dimension, SPS %dx%d, Pixel format %dx%d.", + attributes.width, attributes.height, pix_mp->width, pix_mp->height); return -EINVAL; + } return 0; } @@ -1077,8 +1117,9 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) if (!ctrl) return -EINVAL; - ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); - if (ret) + ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps, + &ctx->coded_fmt.fmt.pix_mp); + if (ret < 0) return ret; h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL); @@ -1175,10 +1216,21 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) return 0; } +static u32 rkvdec_h264_valid_fmt(struct rkvdec_ctx *ctx) +{ + /* + * Only 8 bit 4:0:0 and 4:2:0 formats supported for now. + * The SPS is validated at a different function thus we can assume that + * it is correct. + */ + return V4L2_PIX_FMT_NV12; +} + static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl) { if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) - return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps); + return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps, + &ctx->coded_fmt.fmt.pix_mp); return 0; } @@ -1189,4 +1241,7 @@ const struct rkvdec_coded_fmt_ops rkvdec_h264_fmt_ops = { .stop = rkvdec_h264_stop, .run = rkvdec_h264_run, .try_ctrl = rkvdec_h264_try_ctrl, + .valid_fmt = rkvdec_h264_valid_fmt, + .sps_check = rkvdec_h264_validate_sps, + .get_sps_attributes = rkvdec_h264_get_sps_attributes, }; -- 2.25.1