OSDN Git Service

media: cedrus: h265: Support decoding 10-bit frames
authorJernej Skrabec <jernej.skrabec@gmail.com>
Wed, 9 Nov 2022 18:23:08 +0000 (19:23 +0100)
committerHans Verkuil <hverkuil-cisco@xs4all.nl>
Fri, 18 Nov 2022 14:48:17 +0000 (15:48 +0100)
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>
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus.h
drivers/staging/media/sunxi/cedrus/cedrus_h265.c
drivers/staging/media/sunxi/cedrus/cedrus_regs.h

index 6a2c089..2e860cf 100644 (file)
@@ -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);
index 3f628e6..d8d22c7 100644 (file)
@@ -111,6 +111,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;
index 3f2946c..374eb4c 100644 (file)
@@ -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;
@@ -793,6 +806,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);
 
@@ -858,6 +883,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,
@@ -866,4 +900,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,
 };
index d81f751..d30c3ff 100644 (file)
 
 #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) \