Commit 42a68012 authored by Philipp Zabel's avatar Philipp Zabel Committed by Mauro Carvalho Chehab
Browse files

media: coda: add read-only h.264 decoder profile/level controls



The decoder profile/level controls initially can be used to determine
supported profiles and levels. The values are set for a given stream
once the headers are parsed.

Signed-off-by: default avatarPhilipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 18c227af
Loading
Loading
Loading
Loading
+114 −1
Original line number Diff line number Diff line
@@ -1395,6 +1395,72 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
	return 0;
}

static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value)
{
	if (!ctrl)
		return;

	v4l2_ctrl_lock(ctrl);

	/*
	 * Extend the control range if the parsed stream contains a known but
	 * unsupported value or level.
	 */
	if (value > ctrl->maximum) {
		__v4l2_ctrl_modify_range(ctrl, ctrl->minimum, value,
			ctrl->menu_skip_mask & ~(1 << value),
			ctrl->default_value);
	} else if (value < ctrl->minimum) {
		__v4l2_ctrl_modify_range(ctrl, value, ctrl->maximum,
			ctrl->menu_skip_mask & ~(1 << value),
			ctrl->default_value);
	}

	__v4l2_ctrl_s_ctrl(ctrl, value);

	v4l2_ctrl_unlock(ctrl);
}

static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx)
{
	const char * const *profile_names;
	int profile;

	profile = coda_h264_profile(ctx->params.h264_profile_idc);
	if (profile < 0) {
		v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Profile: %u\n",
			  ctx->params.h264_profile_idc);
		return;
	}

	coda_update_menu_ctrl(ctx->h264_profile_ctrl, profile);

	profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE);

	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Profile: %s\n",
		 profile_names[profile]);
}

static void coda_update_h264_level_ctrl(struct coda_ctx *ctx)
{
	const char * const *level_names;
	int level;

	level = coda_h264_level(ctx->params.h264_level_idc);
	if (level < 0) {
		v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Level: %u\n",
			  ctx->params.h264_level_idc);
		return;
	}

	coda_update_menu_ctrl(ctx->h264_level_ctrl, level);

	level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL);

	v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Parsed H264 Level: %s\n",
		 level_names[level]);
}

static void coda_buf_queue(struct vb2_buffer *vb)
{
	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -1423,8 +1489,11 @@ static void coda_buf_queue(struct vb2_buffer *vb)
			 * whether to enable reordering during sequence
			 * initialization.
			 */
			if (!ctx->params.h264_profile_idc)
			if (!ctx->params.h264_profile_idc) {
				coda_sps_parse_profile(ctx, vb);
				coda_update_h264_profile_ctrl(ctx);
				coda_update_h264_level_ctrl(ctx);
			}
		}

		mutex_lock(&ctx->bitstream_mutex);
@@ -1862,6 +1931,47 @@ static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx)
		V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0);
}

static void coda_decode_ctrls(struct coda_ctx *ctx)
{
	u64 mask;
	u8 max;

	ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
		&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
		~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
		  (1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
		  (1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
		V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
	if (ctx->h264_profile_ctrl)
		ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;

	if (ctx->dev->devtype->product == CODA_HX4 ||
	    ctx->dev->devtype->product == CODA_7541) {
		max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
		mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0));
	} else if (ctx->dev->devtype->product == CODA_960) {
		max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
		mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
			 (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1));
	} else {
		return;
	}
	ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
		&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, mask,
		max);
	if (ctx->h264_level_ctrl)
		ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
}

static int coda_ctrls_setup(struct coda_ctx *ctx)
{
	v4l2_ctrl_handler_init(&ctx->ctrls, 2);
@@ -1875,6 +1985,9 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
			coda_jpeg_encode_ctrls(ctx);
		else
			coda_encode_ctrls(ctx);
	} else {
		if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264)
			coda_decode_ctrls(ctx);
	}

	if (ctx->ctrls.error) {
+2 −0
Original line number Diff line number Diff line
@@ -214,6 +214,8 @@ struct coda_ctx {
	enum v4l2_quantization		quantization;
	struct coda_params		params;
	struct v4l2_ctrl_handler	ctrls;
	struct v4l2_ctrl		*h264_profile_ctrl;
	struct v4l2_ctrl		*h264_level_ctrl;
	struct v4l2_fh			fh;
	int				gopcounter;
	int				runcounter;