From 4d0a5d4bfeee3a097987aa083b1d0bb274651e42 Mon Sep 17 00:00:00 2001 From: Ayoung Sim Date: Tue, 17 Apr 2018 19:21:22 +0900 Subject: [PATCH] media: mfc: DRV4.0: supports the encoder crop option Change-Id: I180f95791d35418053775713aa1456e648c5bf0a Signed-off-by: Ayoung Sim --- .../media/platform/exynos/mfc/s5p_mfc_buf.c | 20 +++--- .../platform/exynos/mfc/s5p_mfc_data_struct.h | 4 ++ .../platform/exynos/mfc/s5p_mfc_debugfs.c | 5 +- .../media/platform/exynos/mfc/s5p_mfc_enc.c | 66 +++++++++++++++++++ .../platform/exynos/mfc/s5p_mfc_enc_param.c | 29 ++++---- .../media/platform/exynos/mfc/s5p_mfc_otf.c | 2 + .../platform/exynos/mfc/s5p_mfc_regs_v10.h | 8 ++- 7 files changed, 104 insertions(+), 30 deletions(-) diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_buf.c b/drivers/media/platform/exynos/mfc/s5p_mfc_buf.c index b30f3e132026..03c2610a6b94 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_buf.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_buf.c @@ -284,17 +284,17 @@ static void mfc_calc_enc_codec_buffer_size(struct s5p_mfc_ctx *ctx) enc = ctx->enc_priv; enc->tmv_buffer_size = 0; - mb_width = WIDTH_MB(ctx->img_width); - mb_height = HEIGHT_MB(ctx->img_height); + mb_width = WIDTH_MB(ctx->crop_width); + mb_height = HEIGHT_MB(ctx->crop_height); - lcu_width = ENC_LCU_WIDTH(ctx->img_width); - lcu_height = ENC_LCU_HEIGHT(ctx->img_height); + lcu_width = ENC_LCU_WIDTH(ctx->crop_width); + lcu_height = ENC_LCU_HEIGHT(ctx->crop_height); /* default recon buffer size, it can be changed in case of 422, 10bit */ enc->luma_dpb_size = - ALIGN(ENC_LUMA_DPB_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_LUMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64); enc->chroma_dpb_size = - ALIGN(ENC_CHROMA_DPB_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_CHROMA_DPB_SIZE(ctx->crop_width, ctx->crop_height), 64); mfc_debug(2, "recon luma size: %zu chroma size: %zu\n", enc->luma_dpb_size, enc->chroma_dpb_size); @@ -337,9 +337,9 @@ static void mfc_calc_enc_codec_buffer_size(struct s5p_mfc_ctx *ctx) case S5P_FIMV_CODEC_VP9_ENC: if (ctx->is_10bit || ctx->is_422format) { enc->luma_dpb_size = - ALIGN(ENC_VP9_LUMA_DPB_10B_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_VP9_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64); enc->chroma_dpb_size = - ALIGN(ENC_VP9_CHROMA_DPB_10B_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_VP9_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64); mfc_debug(2, "VP9 10bit recon luma size: %zu chroma size: %zu\n", enc->luma_dpb_size, enc->chroma_dpb_size); } @@ -356,9 +356,9 @@ static void mfc_calc_enc_codec_buffer_size(struct s5p_mfc_ctx *ctx) case S5P_FIMV_CODEC_BPG_ENC: if (ctx->is_10bit || ctx->is_422format) { enc->luma_dpb_size = - ALIGN(ENC_HEVC_LUMA_DPB_10B_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_HEVC_LUMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64); enc->chroma_dpb_size = - ALIGN(ENC_HEVC_CHROMA_DPB_10B_SIZE(ctx->img_width, ctx->img_height), 64); + ALIGN(ENC_HEVC_CHROMA_DPB_10B_SIZE(ctx->crop_width, ctx->crop_height), 64); mfc_debug(2, "HEVC 10bit or 422 recon luma size: %zu chroma size: %zu\n", enc->luma_dpb_size, enc->chroma_dpb_size); } diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h index ea2428195cbc..cb7b389d1c1c 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_data_struct.h @@ -1288,6 +1288,10 @@ struct s5p_mfc_ctx { int img_width; int img_height; + int crop_width; + int crop_height; + int crop_left; + int crop_top; int dpb_count; int buf_stride; diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c b/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c index 03a98b7759fd..a2b5d7fd4f2c 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_debugfs.c @@ -67,9 +67,10 @@ static int mfc_info_show(struct seq_file *s, void *unused) else codec_name = ctx->dst_fmt->name; - seq_printf(s, "[CTX:%d] codec: %s(%s), width: %d, height: %d, state: %d\n", + seq_printf(s, "[CTX:%d] codec: %s(%s), width: %d, height: %d, crop: %d %d %d %d, state: %d\n", ctx->num, ctx->type == MFCINST_DECODER ? "DEC" : "ENC", codec_name, - ctx->img_width, ctx->img_height, ctx->state); + ctx->img_width, ctx->img_height, ctx->crop_width, ctx->crop_height, + ctx->crop_left, ctx->crop_top, ctx->state); seq_printf(s, " queue(src: %d, dst: %d, src_nal: %d, dst_nal: %d, ref: %d)\n", s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->src_buf_queue), s5p_mfc_get_queue_count(&ctx->buf_queue_lock, &ctx->dst_buf_queue), diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c b/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c index 511233e0bf99..219e59905660 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_enc.c @@ -473,6 +473,12 @@ static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, mfc_info_ctx("fmt - w: %d, h: %d, stride: %d\n", pix_fmt_mp->width, pix_fmt_mp->height, ctx->buf_stride); + /* + * It should be keep till buffer size and stride was calculated. + * And it can be changed to real encoding size, if user call the s_crop. + */ + ctx->crop_width = ctx->img_width; + ctx->crop_height = ctx->img_height; s5p_mfc_enc_calc_src_size(ctx); ctx->output_state = QUEUE_FREE; @@ -481,6 +487,64 @@ static int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, return 0; } +static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *cr) +{ + struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data); + + mfc_debug_enter(); + + cr->c.left = ctx->crop_left; + cr->c.top = ctx->crop_top; + cr->c.width = ctx->crop_width; + cr->c.height = ctx->crop_height; + + mfc_debug(3, "enc crop w: %d, h: %d, offset l: %d t: %d\n", + ctx->crop_width, ctx->crop_height, ctx->crop_left, ctx->crop_top); + + mfc_debug_leave(); + + return 0; +} + +static int vidioc_s_crop(struct file *file, void *priv, const struct v4l2_crop *cr) +{ + struct s5p_mfc_ctx *ctx = fh_to_mfc_ctx(file->private_data); + + mfc_debug_enter(); + + if (cr->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mfc_err_ctx("not supported type (It can only in the source)\n"); + return -EINVAL; + } + + if (cr->c.left < 0 || cr->c.top < 0) { + mfc_err_ctx("crop position is negative\n"); + return -EINVAL; + } + + if ((cr->c.height > ctx->img_height) || (cr->c.top > ctx->img_height) || + (cr->c.width > ctx->img_width) || (cr->c.left > ctx->img_width) || + (cr->c.left <= (ctx->img_width - cr->c.width)) || + (cr->c.top <= (ctx->img_height - cr->c.height))) { + mfc_err_ctx("Out of crop range: (%d,%d,%d,%d) from %dx%d\n", + cr->c.left, cr->c.top, cr->c.width, cr->c.height, + ctx->img_width, ctx->img_height); + return -EINVAL; + } + + ctx->crop_top = cr->c.top; + ctx->crop_left = cr->c.left; + ctx->crop_height = cr->c.height; + ctx->crop_width = cr->c.width; + + mfc_debug(3, "enc original: %dx%d, crop: %dx%d, offset l: %d t: %d\n", + ctx->img_width, ctx->img_height, + ctx->crop_width, ctx->crop_height, + ctx->crop_left, ctx->crop_top); + + return 0; +} + static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *reqbufs) { @@ -1906,6 +1970,8 @@ static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt, .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, + .vidioc_g_crop = vidioc_g_crop, + .vidioc_s_crop = vidioc_s_crop, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c b/drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c index 77ea7292c26e..b913f3e6cda6 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_enc_param.c @@ -187,15 +187,15 @@ static void mfc_set_enc_params(struct s5p_mfc_ctx *ctx) mfc_set_default_params(ctx); /* width */ - MFC_WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH); /* 16 align */ + MFC_WRITEL(ctx->crop_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH); /* height */ - MFC_WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT); /* 16 align */ - /** cropped width */ - MFC_WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH); - /** cropped height */ - MFC_WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT); - /** cropped offset */ - MFC_WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET); + MFC_WRITEL(ctx->crop_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT); + /* cropped offset */ + reg |= (ctx->crop_left & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK) + << S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT; + reg |= (ctx->crop_top & S5P_FIMV_E_FRAME_CROP_OFFSET_MASK) + << S5P_FIMV_E_FRAME_CROP_OFFSET_TOP; + MFC_WRITEL(reg, S5P_FIMV_E_FRAME_CROP_OFFSET); /* multi-slice control */ /* multi-slice MB number or bit size */ @@ -207,7 +207,7 @@ static void mfc_set_enc_params(struct s5p_mfc_ctx *ctx) (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_FIXED_BYTES)){ enc->slice_size.bits = p->slice_bit; } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB_ROW) { - enc->slice_size.mb = p->slice_mb_row * ((ctx->img_width + 15) / 16); + enc->slice_size.mb = p->slice_mb_row * ((ctx->crop_width + 15) / 16); } else { enc->slice_size.mb = 0; enc->slice_size.bits = 0; @@ -523,12 +523,9 @@ void s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) reg |= ((p_264->vui_enable & 0x1) << 30); MFC_WRITEL(reg, S5P_FIMV_E_H264_OPTIONS); - /** height */ - if (p_264->interlace) { - MFC_WRITEL(ctx->img_height >> 1, S5P_FIMV_E_FRAME_HEIGHT); /* 32 align */ - /** cropped height */ - MFC_WRITEL(ctx->img_height >> 1, S5P_FIMV_E_CROPPED_FRAME_HEIGHT); - } + /* cropped height */ + if (p_264->interlace) + MFC_WRITEL(ctx->crop_height >> 1, S5P_FIMV_E_CROPPED_FRAME_HEIGHT); /* loopfilter alpha offset */ reg = MFC_READL(S5P_FIMV_E_H264_LF_ALPHA_OFFSET); @@ -1163,7 +1160,7 @@ void s5p_mfc_set_enc_params_hevc(struct s5p_mfc_ctx *ctx) } /* UHD encoding case */ - if ((ctx->img_width == 3840) && (ctx->img_height == 2160)) { + if (IS_UHD_RES(ctx)) { p_hevc->level = 51; p_hevc->tier_flag = 0; /* this tier_flag can be changed */ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_otf.c b/drivers/media/platform/exynos/mfc/s5p_mfc_otf.c index dfdfa876596b..4797ae3d7a69 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_otf.c +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_otf.c @@ -68,6 +68,8 @@ static int mfc_otf_set_buf_info(struct s5p_mfc_ctx *ctx) ctx->raw_buf.num_planes = ctx->src_fmt->num_planes; ctx->img_width = buf_info->width; ctx->img_height = buf_info->height; + ctx->crop_width = buf_info->width; + ctx->crop_height = buf_info->height; ctx->buf_stride = ALIGN(ctx->img_width, 16); /* calculate source size */ diff --git a/drivers/media/platform/exynos/mfc/s5p_mfc_regs_v10.h b/drivers/media/platform/exynos/mfc/s5p_mfc_regs_v10.h index 3679d1e28045..25039c8e459f 100644 --- a/drivers/media/platform/exynos/mfc/s5p_mfc_regs_v10.h +++ b/drivers/media/platform/exynos/mfc/s5p_mfc_regs_v10.h @@ -237,8 +237,6 @@ #define S5P_FIMV_D_DECODED_CHROMA_ADDR 0xF64C /* Encoder Registers */ -#define S5P_FIMV_E_FRAME_WIDTH 0xF770 -#define S5P_FIMV_E_FRAME_HEIGHT 0xF774 #define S5P_FIMV_E_CROPPED_FRAME_WIDTH 0xF778 #define S5P_FIMV_E_CROPPED_FRAME_HEIGHT 0xF77C #define S5P_FIMV_E_FRAME_CROP_OFFSET 0xF780 @@ -698,6 +696,12 @@ #define S5P_FIMV_D_BLACK_BAR_IMAGE_H_MASK 0xFFFF +/* 0xF780: S5P_FIMV_E_FRAME_CROP_OFFSET */ +#define S5P_FIMV_E_FRAME_CROP_OFFSET_TOP 16 +#define S5P_FIMV_E_FRAME_CROP_OFFSET_LEFT 0 +#define S5P_FIMV_E_FRAME_CROP_OFFSET_MASK 0x3FFF + + /* 0xF784: S5P_FIMV_E_ENC_OPTIONS */ #define S5P_FIMV_E_ENC_OPT_FRAME_SKIP_EN_MASK 0x3 #define S5P_FIMV_E_ENC_OPT_SEQ_HEADER_CONTROL_MASK 0x1 -- 2.20.1