[PATCH v2 09/12] staging: media: rkvdec: h264: Add callbacks for h264

Sebastian Fricke sebastian.fricke at collabora.com
Thu Jan 12 04:56:24 PST 2023


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 at collabora.com>
---
 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



More information about the Linux-rockchip mailing list