media: cedrus: h265: Support decoding 10-bit frames
10-bit frames needs extra buffer space when 8-bit capture format is used. Use previously prepared infrastructure to adjust buffer size. Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com> Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
parent
3d273e81f9
commit
65429ba825
@ -45,6 +45,8 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
|
||||
} else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
|
||||
const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
|
||||
struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
|
||||
unsigned int bit_depth;
|
||||
struct vb2_queue *vq;
|
||||
|
||||
if (sps->chroma_format_idc != 1)
|
||||
/* Only 4:2:0 is supported */
|
||||
@ -63,6 +65,24 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
|
||||
/* Only 8-bit is supported */
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bit_depth = max(sps->bit_depth_luma_minus8,
|
||||
sps->bit_depth_chroma_minus8) + 8;
|
||||
|
||||
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx,
|
||||
V4L2_BUF_TYPE_VIDEO_CAPTURE);
|
||||
|
||||
/*
|
||||
* Bit depth can't be higher than currently set once
|
||||
* buffers are allocated.
|
||||
*/
|
||||
if (vb2_is_busy(vq)) {
|
||||
if (ctx->bit_depth < bit_depth)
|
||||
return -EINVAL;
|
||||
} else {
|
||||
ctx->bit_depth = bit_depth;
|
||||
cedrus_reset_cap_format(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -354,6 +374,7 @@ static int cedrus_open(struct file *file)
|
||||
v4l2_fh_init(&ctx->fh, video_devdata(file));
|
||||
file->private_data = &ctx->fh;
|
||||
ctx->dev = dev;
|
||||
ctx->bit_depth = 8;
|
||||
|
||||
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
|
||||
&cedrus_queue_init);
|
||||
|
@ -119,6 +119,7 @@ struct cedrus_ctx {
|
||||
struct v4l2_pix_format src_fmt;
|
||||
struct v4l2_pix_format dst_fmt;
|
||||
struct cedrus_dec_ops *current_codec;
|
||||
unsigned int bit_depth;
|
||||
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct v4l2_ctrl **ctrls;
|
||||
|
@ -41,6 +41,19 @@ struct cedrus_h265_sram_pred_weight {
|
||||
__s8 offset;
|
||||
} __packed;
|
||||
|
||||
static unsigned int cedrus_h265_2bit_size(unsigned int width,
|
||||
unsigned int height)
|
||||
{
|
||||
/*
|
||||
* Vendor library additionally aligns width and height to 16,
|
||||
* but all capture formats are already aligned to that anyway,
|
||||
* so we can skip that here. All formats are also one form of
|
||||
* YUV 4:2:0 or another, so we can safely assume multiplication
|
||||
* factor of 1.5.
|
||||
*/
|
||||
return ALIGN(width / 4, 32) * height * 3 / 2;
|
||||
}
|
||||
|
||||
static enum cedrus_irq_status cedrus_h265_irq_status(struct cedrus_ctx *ctx)
|
||||
{
|
||||
struct cedrus_dev *dev = ctx->dev;
|
||||
@ -802,6 +815,18 @@ static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
|
||||
VE_DEC_H265_SRAM_OFFSET_PRED_WEIGHT_CHROMA_L1);
|
||||
}
|
||||
|
||||
if (ctx->bit_depth > 8) {
|
||||
unsigned int stride = ALIGN(ctx->dst_fmt.width / 4, 32);
|
||||
|
||||
reg = ctx->dst_fmt.sizeimage -
|
||||
cedrus_h265_2bit_size(ctx->dst_fmt.width,
|
||||
ctx->dst_fmt.height);
|
||||
cedrus_write(dev, VE_DEC_H265_OFFSET_ADDR_FIRST_OUT, reg);
|
||||
|
||||
reg = VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(stride);
|
||||
cedrus_write(dev, VE_DEC_H265_10BIT_CONFIGURE, reg);
|
||||
}
|
||||
|
||||
/* Enable appropriate interruptions. */
|
||||
cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK);
|
||||
|
||||
@ -874,6 +899,15 @@ static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
|
||||
cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_DEC_SLICE);
|
||||
}
|
||||
|
||||
static unsigned int cedrus_h265_extra_cap_size(struct cedrus_ctx *ctx,
|
||||
struct v4l2_pix_format *pix_fmt)
|
||||
{
|
||||
if (ctx->bit_depth > 8)
|
||||
return cedrus_h265_2bit_size(pix_fmt->width, pix_fmt->height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct cedrus_dec_ops cedrus_dec_ops_h265 = {
|
||||
.irq_clear = cedrus_h265_irq_clear,
|
||||
.irq_disable = cedrus_h265_irq_disable,
|
||||
@ -882,4 +916,5 @@ struct cedrus_dec_ops cedrus_dec_ops_h265 = {
|
||||
.start = cedrus_h265_start,
|
||||
.stop = cedrus_h265_stop,
|
||||
.trigger = cedrus_h265_trigger,
|
||||
.extra_cap_size = cedrus_h265_extra_cap_size,
|
||||
};
|
||||
|
@ -498,6 +498,22 @@
|
||||
|
||||
#define VE_DEC_H265_LOW_ADDR (VE_ENGINE_DEC_H265 + 0x80)
|
||||
|
||||
#define VE_DEC_H265_OFFSET_ADDR_FIRST_OUT (VE_ENGINE_DEC_H265 + 0x84)
|
||||
#define VE_DEC_H265_OFFSET_ADDR_SECOND_OUT (VE_ENGINE_DEC_H265 + 0x88)
|
||||
|
||||
#define VE_DEC_H265_SECOND_OUT_FMT_8BIT_PLUS_2BIT 0
|
||||
#define VE_DEC_H265_SECOND_OUT_FMT_P010 1
|
||||
#define VE_DEC_H265_SECOND_OUT_FMT_10BIT_4x4_TILED 2
|
||||
|
||||
#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_OUT_FMT(v) \
|
||||
SHIFT_AND_MASK_BITS(v, 24, 23)
|
||||
#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_ENABLE BIT(22)
|
||||
#define VE_DEC_H265_10BIT_CONFIGURE_SECOND_2BIT_STRIDE(v) \
|
||||
SHIFT_AND_MASK_BITS(v, 21, 11)
|
||||
#define VE_DEC_H265_10BIT_CONFIGURE_FIRST_2BIT_STRIDE(v) \
|
||||
SHIFT_AND_MASK_BITS(v, 10, 0)
|
||||
#define VE_DEC_H265_10BIT_CONFIGURE (VE_ENGINE_DEC_H265 + 0x8c)
|
||||
|
||||
#define VE_DEC_H265_LOW_ADDR_PRIMARY_CHROMA(a) \
|
||||
SHIFT_AND_MASK_BITS(a, 31, 24)
|
||||
#define VE_DEC_H265_LOW_ADDR_SECONDARY_CHROMA(a) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user