mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
media: rkvdec: h264: Validate and use pic width and height in mbs
The width and height in macroblocks is currently configured based on OUTPUT buffer resolution, this works for frame pictures but can cause issues for field pictures. When frame_mbs_only_flag is 0 the height in mbs should be height of the field instead of height of frame. Validate pic_width_in_mbs_minus1 and pic_height_in_map_units_minus1 against OUTPUT buffer resolution and use these values to configure HW. The validation is happening in both try_ctrt() and start() since it is otherwise possible to trick the driver during initialization by changing the OUTPUT format after having set a valid control. [hverkuil: when -> When (first word in a comment block)] Signed-off-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com> Reviewed-by: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
cf76bb4d5e
commit
77e74be830
1 changed files with 62 additions and 19 deletions
|
@ -672,8 +672,17 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx,
|
|||
LOG2_MAX_PIC_ORDER_CNT_LSB_MINUS4);
|
||||
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO),
|
||||
DELTA_PIC_ORDER_ALWAYS_ZERO_FLAG);
|
||||
WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.width, 16), PIC_WIDTH_IN_MBS);
|
||||
WRITE_PPS(DIV_ROUND_UP(ctx->coded_fmt.fmt.pix_mp.height, 16), PIC_HEIGHT_IN_MBS);
|
||||
|
||||
/*
|
||||
* Use the SPS values since they are already in macroblocks
|
||||
* dimensions, height can be field height (halved) if
|
||||
* V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY is not set and also it allows
|
||||
* decoding smaller images into larger allocation which can be used
|
||||
* to implementing SVC spatial layer support.
|
||||
*/
|
||||
WRITE_PPS(sps->pic_width_in_mbs_minus1 + 1, PIC_WIDTH_IN_MBS);
|
||||
WRITE_PPS(sps->pic_height_in_map_units_minus1 + 1, PIC_HEIGHT_IN_MBS);
|
||||
|
||||
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY),
|
||||
FRAME_MBS_ONLY_FLAG);
|
||||
WRITE_PPS(!!(sps->flags & V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD),
|
||||
|
@ -1035,13 +1044,61 @@ 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)
|
||||
{
|
||||
unsigned int width, height;
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
return -EINVAL;
|
||||
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
|
||||
/* Luma and chroma bit depth mismatch */
|
||||
return -EINVAL;
|
||||
if (sps->bit_depth_luma_minus8 != 0)
|
||||
/* Only 8-bit is supported */
|
||||
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)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rkvdec_h264_start(struct rkvdec_ctx *ctx)
|
||||
{
|
||||
struct rkvdec_dev *rkvdec = ctx->dev;
|
||||
struct rkvdec_h264_priv_tbl *priv_tbl;
|
||||
struct rkvdec_h264_ctx *h264_ctx;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
int ret;
|
||||
|
||||
ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl,
|
||||
V4L2_CID_STATELESS_H264_SPS);
|
||||
if (!ctrl)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
h264_ctx = kzalloc(sizeof(*h264_ctx), GFP_KERNEL);
|
||||
if (!h264_ctx)
|
||||
return -ENOMEM;
|
||||
|
@ -1139,23 +1196,9 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx)
|
|||
|
||||
static int rkvdec_h264_try_ctrl(struct rkvdec_ctx *ctx, struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
if (ctrl->id == V4L2_CID_STATELESS_H264_SPS) {
|
||||
const struct v4l2_ctrl_h264_sps *sps = ctrl->p_new.p_h264_sps;
|
||||
/*
|
||||
* 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 */
|
||||
return -EINVAL;
|
||||
if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
|
||||
/* Luma and chroma bit depth mismatch */
|
||||
return -EINVAL;
|
||||
if (sps->bit_depth_luma_minus8 != 0)
|
||||
/* Only 8-bit is supported */
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ctrl->id == V4L2_CID_STATELESS_H264_SPS)
|
||||
return rkvdec_h264_validate_sps(ctx, ctrl->p_new.p_h264_sps);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue