media: cedrus: hevc: Add support for scaling lists
authorJernej Skrabec <jernej.skrabec@gmail.com>
Sun, 6 Jun 2021 06:50:50 +0000 (08:50 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 30 Sep 2021 08:07:38 +0000 (10:07 +0200)
HEVC frames may use scaling list feature. Add support for it.

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+huawei@kernel.org>
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus.h
drivers/staging/media/sunxi/cedrus/cedrus_dec.c
drivers/staging/media/sunxi/cedrus/cedrus_h265.c
drivers/staging/media/sunxi/cedrus/cedrus_regs.h

index c0d005dafc6c04aaab02c14d8541258c9260e443..8114e216701321cd0193ed83cc4a2293963e0f9a 100644 (file)
@@ -135,6 +135,12 @@ static const struct cedrus_control cedrus_controls[] = {
                },
                .codec          = CEDRUS_CODEC_H265,
        },
+       {
+               .cfg = {
+                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
+               },
+               .codec          = CEDRUS_CODEC_H265,
+       },
        {
                .cfg = {
                        .id     = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
index 88afba17b78bd3f314eb29fbd7bbcbb2e88a77d5..9c7bfd2b661600d5279b02995e5d6a884ea654b2 100644 (file)
@@ -78,6 +78,7 @@ struct cedrus_h265_run {
        const struct v4l2_ctrl_hevc_pps                 *pps;
        const struct v4l2_ctrl_hevc_slice_params        *slice_params;
        const struct v4l2_ctrl_hevc_decode_params       *decode_params;
+       const struct v4l2_ctrl_hevc_scaling_matrix      *scaling_matrix;
 };
 
 struct cedrus_vp8_run {
index 40e8c4123f76a6928a5338534236a5f89e224a37..a16c1422558f542eaa2be7a60b302131edecf1ba 100644 (file)
@@ -72,6 +72,8 @@ void cedrus_device_run(void *priv)
                        V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
                run.h265.decode_params = cedrus_find_control_data(ctx,
                        V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
+               run.h265.scaling_matrix = cedrus_find_control_data(ctx,
+                       V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
                break;
 
        case V4L2_PIX_FMT_VP8_FRAME:
index ef0311a16d019fd596be28954168dc461e55f1c6..3d9561d4aadb96990ccef13097fdc6a18430e595 100644 (file)
@@ -238,6 +238,69 @@ static void cedrus_h265_skip_bits(struct cedrus_dev *dev, int num)
        }
 }
 
+static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
+                                          struct cedrus_run *run)
+{
+       const struct v4l2_ctrl_hevc_scaling_matrix *scaling;
+       struct cedrus_dev *dev = ctx->dev;
+       u32 i, j, k, val;
+
+       scaling = run->h265.scaling_matrix;
+
+       cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF0,
+                    (scaling->scaling_list_dc_coef_32x32[1] << 24) |
+                    (scaling->scaling_list_dc_coef_32x32[0] << 16) |
+                    (scaling->scaling_list_dc_coef_16x16[1] << 8) |
+                    (scaling->scaling_list_dc_coef_16x16[0] << 0));
+
+       cedrus_write(dev, VE_DEC_H265_SCALING_LIST_DC_COEF1,
+                    (scaling->scaling_list_dc_coef_16x16[5] << 24) |
+                    (scaling->scaling_list_dc_coef_16x16[4] << 16) |
+                    (scaling->scaling_list_dc_coef_16x16[3] << 8) |
+                    (scaling->scaling_list_dc_coef_16x16[2] << 0));
+
+       cedrus_h265_sram_write_offset(dev, VE_DEC_H265_SRAM_OFFSET_SCALING_LISTS);
+
+       for (i = 0; i < 6; i++)
+               for (j = 0; j < 8; j++)
+                       for (k = 0; k < 8; k += 4) {
+                               val = ((u32)scaling->scaling_list_8x8[i][j + (k + 3) * 8] << 24) |
+                                     ((u32)scaling->scaling_list_8x8[i][j + (k + 2) * 8] << 16) |
+                                     ((u32)scaling->scaling_list_8x8[i][j + (k + 1) * 8] << 8) |
+                                     scaling->scaling_list_8x8[i][j + k * 8];
+                               cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+                       }
+
+       for (i = 0; i < 2; i++)
+               for (j = 0; j < 8; j++)
+                       for (k = 0; k < 8; k += 4) {
+                               val = ((u32)scaling->scaling_list_32x32[i][j + (k + 3) * 8] << 24) |
+                                     ((u32)scaling->scaling_list_32x32[i][j + (k + 2) * 8] << 16) |
+                                     ((u32)scaling->scaling_list_32x32[i][j + (k + 1) * 8] << 8) |
+                                     scaling->scaling_list_32x32[i][j + k * 8];
+                               cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+                       }
+
+       for (i = 0; i < 6; i++)
+               for (j = 0; j < 8; j++)
+                       for (k = 0; k < 8; k += 4) {
+                               val = ((u32)scaling->scaling_list_16x16[i][j + (k + 3) * 8] << 24) |
+                                     ((u32)scaling->scaling_list_16x16[i][j + (k + 2) * 8] << 16) |
+                                     ((u32)scaling->scaling_list_16x16[i][j + (k + 1) * 8] << 8) |
+                                     scaling->scaling_list_16x16[i][j + k * 8];
+                               cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+                       }
+
+       for (i = 0; i < 6; i++)
+               for (j = 0; j < 4; j++) {
+                       val = ((u32)scaling->scaling_list_4x4[i][j + 12] << 24) |
+                             ((u32)scaling->scaling_list_4x4[i][j + 8] << 16) |
+                             ((u32)scaling->scaling_list_4x4[i][j + 4] << 8) |
+                             scaling->scaling_list_4x4[i][j];
+                       cedrus_write(dev, VE_DEC_H265_SRAM_DATA, val);
+               }
+}
+
 static void cedrus_h265_setup(struct cedrus_ctx *ctx,
                              struct cedrus_run *run)
 {
@@ -527,7 +590,12 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        /* Scaling list. */
 
-       reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+       if (sps->flags & V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED) {
+               cedrus_h265_write_scaling_list(ctx, run);
+               reg = VE_DEC_H265_SCALING_LIST_CTRL0_FLAG_ENABLED;
+       } else {
+               reg = VE_DEC_H265_SCALING_LIST_CTRL0_DEFAULT;
+       }
        cedrus_write(dev, VE_DEC_H265_SCALING_LIST_CTRL0, reg);
 
        /* Neightbor information address. */
index 92ace87c1c7d1d72dcb53290f3aba668f986aeaa..bdb062ad86823c3d17371d9911ac22593e6f1266 100644 (file)
 #define VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR    (VE_ENGINE_DEC_H265 + 0x64)
 #define VE_DEC_H265_TILE_START_CTB             (VE_ENGINE_DEC_H265 + 0x68)
 #define VE_DEC_H265_TILE_END_CTB               (VE_ENGINE_DEC_H265 + 0x6c)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF0      (VE_ENGINE_DEC_H265 + 0x78)
+#define VE_DEC_H265_SCALING_LIST_DC_COEF1      (VE_ENGINE_DEC_H265 + 0x7c)
 
 #define VE_DEC_H265_LOW_ADDR                   (VE_ENGINE_DEC_H265 + 0x80)