From: Nagaraju Siddineni <[email protected]> - Add for MPEG‑4, H.263, VP8/VP9, HEVC codec support with extended contexts and buffer allocation. - Implement LCU sizing, motion‑estimation buffers, and align scratch buffers. - Unify ROI buffer handling across all encoders. - Register additional pixel formats (`mfc_format.h`). - Enhance QoS weighting and B‑frame/reference‑count logic. - Introduce hierarchical‑coding controls (layer count, per‑layer bitrate) and SVC for HEVC, VP8, VP9. - Update timestamp handling for H.263 and improved VP8 buffer‑exhaustion error reporting.
Signed-off-by: Nagaraju Siddineni <[email protected]> Signed-off-by: Himanshu Dewangan <[email protected]> --- .../samsung/exynos-mfc/base/mfc_buf.c | 71 ++++++++++++++++++- .../samsung/exynos-mfc/base/mfc_format.h | 40 +++++++++++ .../samsung/exynos-mfc/base/mfc_qos.c | 23 +++++- .../samsung/exynos-mfc/base/mfc_utils.h | 10 ++- .../samsung/exynos-mfc/mfc_core_buf_ctrl.c | 59 ++++++++++++++- .../samsung/exynos-mfc/mfc_core_isr.c | 2 + 6 files changed, 198 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c b/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c index 0186fe3327f1..164852e83e7d 100644 --- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c +++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_buf.c @@ -133,10 +133,17 @@ int mfc_alloc_instance_context(struct mfc_core_ctx *core_ctx) core_ctx->instance_ctx_buf.size = buf_size->other_dec_ctx; break; case MFC_REG_CODEC_H264_ENC: + case MFC_REG_CODEC_AV1_DEC: core_ctx->instance_ctx_buf.size = buf_size->h264_enc_ctx; break; - case MFC_REG_CODEC_AV1_DEC: - core_ctx->instance_ctx_buf.size = buf_size->av1_dec_ctx; + case MFC_REG_CODEC_HEVC_ENC: + core_ctx->instance_ctx_buf.size = buf_size->hevc_enc_ctx; + break; + case MFC_REG_CODEC_MPEG4_ENC: + case MFC_REG_CODEC_H263_ENC: + case MFC_REG_CODEC_VP8_ENC: + case MFC_REG_CODEC_VP9_ENC: + core_ctx->instance_ctx_buf.size = buf_size->other_enc_ctx; break; default: core_ctx->instance_ctx_buf.size = 0; @@ -256,6 +263,7 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx) struct mfc_ctx *ctx = core_ctx->ctx; struct mfc_enc *enc; unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; enc = ctx->enc_priv; enc->tmv_buffer_size = 0; @@ -263,6 +271,9 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx) mb_width = WIDTH_MB(ctx->crop_width); mb_height = HEIGHT_MB(ctx->crop_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->crop_width, ctx->crop_height), SZ_64); @@ -293,6 +304,47 @@ static void __mfc_enc_calc_codec_buffer_size(struct mfc_core_ctx *core_ctx) (ctx->dpb_count * (enc->luma_dpb_size + enc->chroma_dpb_size + enc->me_buffer_size)); break; + case MFC_REG_CODEC_MPEG4_ENC: + case MFC_REG_CODEC_H263_ENC: + enc->me_buffer_size = + ALIGN(ENC_V100_MPEG4_ME_SIZE(mb_width, mb_height), SZ_256); + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256); + core_ctx->codec_buf.size = + ctx->scratch_buf_size + enc->tmv_buffer_size + + (ctx->dpb_count * (enc->luma_dpb_size + + enc->chroma_dpb_size + enc->me_buffer_size)); + break; + case MFC_REG_CODEC_VP8_ENC: + enc->me_buffer_size = + ALIGN(ENC_V100_VP8_ME_SIZE(mb_width, mb_height), SZ_256); + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256); + core_ctx->codec_buf.size = + ctx->scratch_buf_size + enc->tmv_buffer_size + + (ctx->dpb_count * (enc->luma_dpb_size + + enc->chroma_dpb_size + enc->me_buffer_size)); + break; + case MFC_REG_CODEC_VP9_ENC: + enc->me_buffer_size = + ALIGN(ENC_V100_VP9_ME_SIZE(lcu_width, lcu_height), SZ_256); + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256); + core_ctx->codec_buf.size = + ctx->scratch_buf_size + enc->tmv_buffer_size + + (ctx->dpb_count * (enc->luma_dpb_size + + enc->chroma_dpb_size + enc->me_buffer_size)); + break; + case MFC_REG_CODEC_HEVC_ENC: + enc->me_buffer_size = + ALIGN(ENC_V100_HEVC_ME_SIZE(lcu_width, lcu_height), SZ_256); + + ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size, SZ_256); + core_ctx->codec_buf.size = + ctx->scratch_buf_size + enc->tmv_buffer_size + + (ctx->dpb_count * (enc->luma_dpb_size + + enc->chroma_dpb_size + enc->me_buffer_size)); + break; default: core_ctx->codec_buf.size = 0; mfc_err("invalid codec type: %d\n", ctx->codec_mode); @@ -493,6 +545,7 @@ int mfc_alloc_enc_roi_buffer(struct mfc_core_ctx *core_ctx) struct mfc_ctx *ctx = core_ctx->ctx; struct mfc_enc *enc = ctx->enc_priv; unsigned int mb_width, mb_height; + unsigned int lcu_width = 0, lcu_height = 0; size_t size; int i; @@ -503,6 +556,20 @@ int mfc_alloc_enc_roi_buffer(struct mfc_core_ctx *core_ctx) case MFC_REG_CODEC_H264_ENC: size = ((((mb_width * (mb_height + 1) / 2) + 15) / 16) * 16) * 2; break; + case MFC_REG_CODEC_MPEG4_ENC: + case MFC_REG_CODEC_VP8_ENC: + size = mb_width * mb_height; + break; + case MFC_REG_CODEC_VP9_ENC: + lcu_width = (ctx->crop_width + 63) / 64; + lcu_height = (ctx->crop_height + 63) / 64; + size = lcu_width * lcu_height * 4; + break; + case MFC_REG_CODEC_HEVC_ENC: + lcu_width = (ctx->crop_width + 31) / 32; + lcu_height = (ctx->crop_height + 31) / 32; + size = lcu_width * lcu_height; + break; default: mfc_debug(2, "ROI not supported codec type(%d). Allocate with default size\n", diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h b/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h index e8573d6b6005..070c669e1d82 100644 --- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h +++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_format.h @@ -271,6 +271,46 @@ static struct mfc_fmt mfc_formats[] = { .num_planes = 1, .mem_planes = 1, }, + { + .name = "ENC MPEG4", + .fourcc = V4L2_PIX_FMT_MPEG4, + .codec_mode = MFC_REG_CODEC_MPEG4_ENC, + .type = MFC_FMT_STREAM | MFC_FMT_ENC, + .num_planes = 1, + .mem_planes = 1, + }, + { + .name = "ENC H263", + .fourcc = V4L2_PIX_FMT_H263, + .codec_mode = MFC_REG_CODEC_H263_ENC, + .type = MFC_FMT_STREAM | MFC_FMT_ENC, + .num_planes = 1, + .mem_planes = 1, + }, + { + .name = "ENC VP8", + .fourcc = V4L2_PIX_FMT_VP8, + .codec_mode = MFC_REG_CODEC_VP8_ENC, + .type = MFC_FMT_STREAM | MFC_FMT_ENC, + .num_planes = 1, + .mem_planes = 1, + }, + { + .name = "ENC VP9", + .fourcc = V4L2_PIX_FMT_VP9, + .codec_mode = MFC_REG_CODEC_VP9_ENC, + .type = MFC_FMT_STREAM | MFC_FMT_ENC, + .num_planes = 1, + .mem_planes = 1, + }, + { + .name = "ENC HEVC", + .fourcc = V4L2_PIX_FMT_HEVC, + .codec_mode = MFC_REG_CODEC_HEVC_ENC, + .type = MFC_FMT_STREAM | MFC_FMT_ENC, + .num_planes = 1, + .mem_planes = 1, + }, }; #endif /* __MFC_FORMAT_H */ diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c b/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c index 40541e2d626f..73058ace1fd6 100644 --- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c +++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_qos.c @@ -58,6 +58,7 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l break; case MFC_REG_CODEC_VP8_DEC: + case MFC_REG_CODEC_VP8_ENC: weight = (weight * 100) / qos_weight->weight_vp8_vp9; mfc_ctx_debug(3, "[QoS] vp8, vp9 codec, weight: %d\n", weight / 10); if (num_planes == 3) { @@ -80,12 +81,26 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l } break; + case MFC_REG_CODEC_HEVC_ENC: + weight = (weight * 100) / qos_weight->weight_h264_hevc; + mfc_ctx_debug(3, "[QoS] h264, hevc codec, weight: %d\n", weight / 10); + if (num_planes == 3) { + weight = (weight * 100) / qos_weight->weight_3plane; + mfc_ctx_debug(3, "[QoS] 3 plane, weight: %d\n", weight / 10); + } + if (ctx->is_422) { + weight = (weight * 100) / qos_weight->weight_422; + mfc_ctx_debug(3, "[QoS] 422foramt, weight: %d\n", weight / 10); + } + break; + case MFC_REG_CODEC_AV1_DEC: weight = (weight * 100) / qos_weight->weight_av1; mfc_ctx_debug(3, "[QoS] av1 codec, weight: %d\n", weight / 10); break; case MFC_REG_CODEC_VP9_DEC: + case MFC_REG_CODEC_VP9_ENC: weight = (weight * 100) / qos_weight->weight_vp8_vp9; mfc_ctx_debug(3, "[QoS] vp8, vp9 codec, weight: %d\n", weight / 10); @@ -109,6 +124,8 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l case MFC_REG_CODEC_VC1_RCV_DEC: case MFC_REG_CODEC_VC1_DEC: case MFC_REG_CODEC_MPEG2_DEC: + case MFC_REG_CODEC_MPEG4_ENC: + case MFC_REG_CODEC_H263_ENC: weight = (weight * 100) / qos_weight->weight_other_codec; mfc_ctx_debug(3, "[QoS] other codec, weight: %d\n", weight / 10); break; @@ -122,9 +139,13 @@ static inline unsigned long __mfc_qos_add_weight(struct mfc_ctx *ctx, unsigned l if (mfc_is_enc_bframe(ctx)) { weight = (weight * 100) / qos_weight->weight_bframe; mfc_ctx_debug(3, "[QoS] B frame encoding, weight: %d\n", weight / 10); - } else if (IS_H264_ENC(ctx) && (p->num_refs_for_p >= 2)) { + } else if ((IS_H264_ENC(ctx) || IS_HEVC_ENC(ctx) || IS_VP8_ENC(ctx) || + IS_VP9_ENC(ctx)) && (p->num_refs_for_p >= 2)) { weight = (weight * 100) / qos_weight->weight_num_of_ref; mfc_ctx_debug(3, "[QoS] num of ref >= 2, weight: %d\n", weight / 10); + } else if (IS_HEVC_ENC(ctx) && p->codec.hevc.general_pb_enable) { + weight = (weight * 100) / qos_weight->weight_gpb; + mfc_ctx_debug(3, "[QoS] Genaral PB, weight: %d\n", weight / 10); } } if (dec) { diff --git a/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h b/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h index a127f330fe16..8526f5676761 100644 --- a/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h +++ b/drivers/media/platform/samsung/exynos-mfc/base/mfc_utils.h @@ -229,7 +229,11 @@ static inline int mfc_is_enc_bframe(struct mfc_ctx *ctx) if (IS_H264_ENC(ctx)) { num_hier_layer = p->codec.h264.num_hier_layer; hier_qp_type = (int)p->codec.h264.hier_qp_type; + } else if (IS_HEVC_ENC(ctx)) { + num_hier_layer = p->codec.hevc.num_hier_layer; + hier_qp_type = (int)p->codec.hevc.hier_qp_type; } + if (enc->params.num_b_frame || (num_hier_layer >= 2 && hier_qp_type == V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B)) @@ -402,7 +406,11 @@ static inline int mfc_enc_get_ts_delta(struct mfc_ctx *ctx) * so thie is also divided into pre-calculated 100. * (Preventing both overflow and calculation duplication) */ - ts_delta = ctx->src_ts.ts_last_interval / 100; + if (IS_H263_ENC(ctx)) + ts_delta = ctx->src_ts.ts_last_interval * + p->rc_framerate_res / USEC_PER_SEC; + else + ts_delta = ctx->src_ts.ts_last_interval / 100; } return ts_delta; } diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c b/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c index cc0a20bea33a..11e9c2622242 100644 --- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c +++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_buf_ctrl.c @@ -11,6 +11,25 @@ #include "mfc_core_reg_api.h" +static int __mfc_enc_check_adaptive_temporal_svc(int id, + struct mfc_enc_params *p, + struct temporal_layer_info + *temporal_LC) +{ + unsigned int new_num_layer = temporal_LC->temporal_layer_count; + unsigned int old_num_layer, ref_type; + + if (id == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) { + old_num_layer = p->codec.hevc.num_hier_layer; + ref_type = p->codec.hevc.hier_ref_type; + if (ref_type == 0 && old_num_layer != new_num_layer) + if (new_num_layer == 1 || old_num_layer == 1) + return 1; + } + + return 0; +} + static void __mfc_enc_store_buf_ctrls_temporal_svc(int id, struct mfc_enc_params *p, struct temporal_layer_info @@ -26,6 +45,24 @@ static void __mfc_enc_store_buf_ctrls_temporal_svc(int id, p->codec.h264.hier_bit_layer[i] = temporal_LC->temporal_layer_bitrate[i]; break; + case V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH: + p->codec.hevc.num_hier_layer = num_layer & 0x7; + for (i = 0; i < (num_layer & 0x7); i++) + p->codec.hevc.hier_bit_layer[i] = + temporal_LC->temporal_layer_bitrate[i]; + break; + case V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH: + p->codec.vp8.num_hier_layer = num_layer & 0x7; + for (i = 0; i < (num_layer & 0x7); i++) + p->codec.vp8.hier_bit_layer[i] = + temporal_LC->temporal_layer_bitrate[i]; + break; + case V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH: + p->codec.vp9.num_hier_layer = num_layer & 0x7; + for (i = 0; i < (num_layer & 0x7); i++) + p->codec.vp9.hier_bit_layer[i] = + temporal_LC->temporal_layer_bitrate[i]; + break; default: break; } @@ -43,12 +80,21 @@ static void __mfc_core_enc_set_buf_ctrls_temporal_svc(struct mfc_core *core, struct mfc_enc_params *p = &enc->params; if (buf_ctrl->id - == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH) { + == V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_CH || + buf_ctrl->id + == V4L2_CID_MPEG_VIDEO_VP8_HIERARCHICAL_CODING_LAYER_CH || + buf_ctrl->id + == V4L2_CID_MPEG_VIDEO_VP9_HIERARCHICAL_CODING_LAYER_CH || + buf_ctrl->id + == V4L2_CID_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_LAYER_CH) { memcpy(&temporal_LC, enc->sh_handle_svc.vaddr, sizeof(struct temporal_layer_info)); - if ((temporal_LC.temporal_layer_count & 0x7) < 1) { + if (((temporal_LC.temporal_layer_count & 0x7) < 1) || + (temporal_LC.temporal_layer_count > 3 && IS_VP8_ENC(ctx)) || + (temporal_LC.temporal_layer_count > 3 && + IS_VP9_ENC(ctx))) { /* clear NUM_T_LAYER_CHANGE */ value = MFC_CORE_READL(buf_ctrl->flag_addr); value &= ~BIT(10); @@ -61,7 +107,14 @@ static void __mfc_core_enc_set_buf_ctrls_temporal_svc(struct mfc_core *core, value = MFC_CORE_READL(buf_ctrl->flag_addr); value &= ~(0x3 << 21); - + /* Adaptive temporal SVC(layer count 1: IPPP, others: H-B) */ + if (__mfc_enc_check_adaptive_temporal_svc + (buf_ctrl->id, p, &temporal_LC)) { + if (temporal_LC.temporal_layer_count > 1) + value |= BIT(21); + else + value |= (0x2 << 21); + } MFC_CORE_WRITEL(value, buf_ctrl->flag_addr); /* Store temporal layer information */ diff --git a/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c b/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c index 1a3cf7e76e29..9c5be84fcbc6 100644 --- a/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c +++ b/drivers/media/platform/samsung/exynos-mfc/mfc_core_isr.c @@ -1883,6 +1883,8 @@ static inline void __mfc_handle_nal_abort(struct mfc_core *core, if (ctx->type == MFCINST_ENCODER) { mfc_change_state(core_ctx, MFCINST_RUNNING_BUF_FULL); enc->buf_full = 0; + if (IS_VP8_ENC(ctx)) + mfc_err("stream buffer size isn't enough\n"); __mfc_handle_stream(core, ctx, reason); } else { mfc_change_state(core_ctx, MFCINST_ABORT); -- 2.34.1
