diff --git a/mpp/hal/inc/hal_h264e_api.h b/mpp/hal/inc/hal_h264e_api.h index 67f6ad47..187c5b4f 100644 --- a/mpp/hal/inc/hal_h264e_api.h +++ b/mpp/hal/inc/hal_h264e_api.h @@ -25,15 +25,6 @@ extern "C" { extern const MppHalApi hal_api_h264e; -MPP_RET hal_h264e_init (void *hal, MppHalCfg *cfg); -MPP_RET hal_h264e_deinit (void *hal); -MPP_RET hal_h264e_gen_regs(void *hal, HalTaskInfo *task); -MPP_RET hal_h264e_start (void *hal, HalTaskInfo *task); -MPP_RET hal_h264e_wait (void *hal, HalTaskInfo *task); -MPP_RET hal_h264e_reset (void *hal); -MPP_RET hal_h264e_flush (void *hal); -MPP_RET hal_h264e_control (void *hal, MpiCmd cmd_type, void *param); - #ifdef __cplusplus } #endif diff --git a/mpp/hal/inc/mpp_enc_hal.h b/mpp/hal/inc/mpp_enc_hal.h new file mode 100644 index 00000000..588440fd --- /dev/null +++ b/mpp/hal/inc/mpp_enc_hal.h @@ -0,0 +1,76 @@ +/* + * Copyright 2015 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MPP_ENC_HAL_H__ +#define __MPP_ENC_HAL_H__ + +#include "mpp_hal.h" + +typedef struct MppEncHalCfg_t { + // input for encoder + MppCodingType coding; + MppEncCfgSet *set; + MppEncCfgSet *cfg; + + // output for enc_impl + HalWorkMode work_mode; + MppDeviceId device_id; +} MppEncHalCfg; + +typedef struct MppEncHalApi_t { + char *name; + MppCodingType coding; + RK_U32 ctx_size; + RK_U32 flag; + + MPP_RET (*init)(void *ctx, MppEncHalCfg *cfg); + MPP_RET (*deinit)(void *ctx); + + // configure function + MPP_RET (*get_task)(void *ctx, HalEncTask *task); + MPP_RET (*gen_regs)(void *ctx, HalEncTask *task); + + // hw operation function + MPP_RET (*start)(void *ctx, HalEncTask *task); + MPP_RET (*wait)(void *ctx, HalEncTask *task); + + // return function + MPP_RET (*ret_task)(void *ctx, HalEncTask *task); +} MppEncHalApi; + +typedef void* MppEncHal; + +#ifdef __cplusplus +extern "C" { +#endif + +MPP_RET mpp_enc_hal_init(MppEncHal *ctx, MppEncHalCfg *cfg); +MPP_RET mpp_enc_hal_deinit(MppEncHal ctx); + +MPP_RET mpp_enc_hal_get_task(MppEncHal ctx, HalEncTask *task); +MPP_RET mpp_enc_hal_gen_regs(MppEncHal ctx, HalEncTask *task); + +// start / wait hardware +MPP_RET mpp_enc_hal_start(MppEncHal ctx, HalEncTask *task); +MPP_RET mpp_enc_hal_wait(MppEncHal ctx, HalEncTask *task); + +MPP_RET mpp_enc_hal_ret_task(MppEncHal ctx, HalEncTask *task); + +#ifdef __cplusplus +} +#endif + +#endif /*__MPP_ENC_HAL_H__*/ diff --git a/mpp/hal/vpu/h264e/CMakeLists.txt b/mpp/hal/vpu/h264e/CMakeLists.txt index 3d0b64fe..f021ac7c 100644 --- a/mpp/hal/vpu/h264e/CMakeLists.txt +++ b/mpp/hal/vpu/h264e/CMakeLists.txt @@ -1,6 +1,7 @@ # vim: syntax=cmake include_directories(.) include_directories(../../common/h264/) +include_directories(../../../codec/enc/h264/) # hal h264 header set(HAL_H264E_HDR @@ -9,6 +10,8 @@ set(HAL_H264E_HDR # hal h264 encoder sourse set(HAL_H264E_SRC + hal_h264e_vepu2_v2.c + hal_h264e_vepu_v2.c hal_h264e_vpu_tbl.c hal_h264e_vepu2.c hal_h264e_vepu1.c diff --git a/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.c b/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.c new file mode 100644 index 00000000..064df821 --- /dev/null +++ b/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.c @@ -0,0 +1,806 @@ +/* + * Copyright 2015 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MODULE_TAG "hal_h264e_vepu2_v2" + +#include + +#include "mpp_env.h" +#include "mpp_mem.h" +#include "mpp_frame.h" +#include "mpp_common.h" +#include "mpp_device.h" +#include "mpp_rc.h" + +#include "mpp_enc_hal.h" +#include "h264e_debug.h" +#include "h264e_syntax_new.h" +#include "h264e_slice.h" +#include "h264e_stream.h" + +#include "hal_h264e_com.h" +#include "hal_h264e_vpu_tbl.h" +#include "hal_h264e_vepu_v2.h" + +#include "hal_h264e_vepu2_reg_tbl.h" + +typedef struct HalH264eVepu2Ctx_t { + MppEncCfgSet *cfg; + + MppDevCtx dev_ctx; + RK_S32 frame_cnt; + + /* buffers management */ + HalH264eVepuBufs hw_bufs; + + /* preprocess config */ + HalH264eVepuPrep hw_prep; + + /* input / recon / refer address config */ + HalH264eVepuAddr hw_addr; + + /* macroblock ratecontrol config */ + HalH264eVepuMbRc hw_mbrc; + + /* syntax for input from enc_impl */ + RK_U32 updated; + SynH264eSps *sps; + SynH264ePps *pps; + H264eSlice *slice; + H264eFrmInfo *frms; + H264eReorderInfo *reorder; + H264eMarkingInfo *marking; + RcSyntax *rc_syn; + + /* special TSVC stream header fixup */ + size_t buf_size; + RK_U8 *src_buf; + RK_U8 *dst_buf; + + /* syntax for output to enc_impl */ + MppRcHalCfg hal_rc_cfg; + + /* vepu2 macroblock ratecontrol context */ + HalH264eVepuMbRcCtx rc_ctx; + + H264eVpu2RegSet regs_set; + H264eVpu2RegSet regs_get; +} HalH264eVepu2Ctx; + +static MPP_RET hal_h264e_vepu2_deinit_v2(void *hal) +{ + HalH264eVepu2Ctx *p = (HalH264eVepu2Ctx *)hal; + + hal_h264e_dbg_func("enter %p\n", p); + + if (p->dev_ctx) { + mpp_device_deinit(p->dev_ctx); + p->dev_ctx = NULL; + } + + h264e_vepu_buf_deinit(&p->hw_bufs); + + if (p->rc_ctx) { + h264e_vepu_mbrc_deinit(p->rc_ctx); + p->rc_ctx = NULL; + } + + MPP_FREE(p->src_buf); + MPP_FREE(p->dst_buf); + + hal_h264e_dbg_func("leave %p\n", p); + + return MPP_OK; +} + +static MPP_RET hal_h264e_vepu2_init_v2(void *hal, MppEncHalCfg *cfg) +{ + HalH264eVepu2Ctx *p = (HalH264eVepu2Ctx *)hal; + MPP_RET ret = MPP_OK; + MppDevCfg dev_cfg = { + .type = MPP_CTX_ENC, /* type */ + .coding = MPP_VIDEO_CodingAVC, /* coding */ + .platform = 0, /* platform */ + .pp_enable = 0, /* pp_enable */ + }; + + hal_h264e_dbg_func("enter %p\n", p); + + p->cfg = cfg->cfg; + + ret = mpp_device_init(&p->dev_ctx, &dev_cfg); + if (ret) { + mpp_err_f("mpp_device_init failed ret: %d\n", ret); + goto DONE; + } + + ret = h264e_vepu_buf_init(&p->hw_bufs); + if (ret) { + mpp_err_f("init vepu buffer failed ret: %d\n", ret); + goto DONE; + } + + ret = h264e_vepu_mbrc_init(&p->rc_ctx, &p->hw_mbrc); + if (ret) { + mpp_err_f("init mb rate control failed ret: %d\n", ret); + goto DONE; + } + + /* create buffer to TSVC stream */ + p->buf_size = SZ_128K; + p->src_buf = mpp_calloc(RK_U8, p->buf_size); + p->dst_buf = mpp_calloc(RK_U8, p->buf_size); + +DONE: + if (ret) + hal_h264e_vepu2_deinit_v2(hal); + + hal_h264e_dbg_func("leave %p\n", p); + return ret; +} + +static RK_U32 update_vepu2_syntax(HalH264eVepu2Ctx *ctx, MppSyntax *syntax) +{ + H264eSyntaxDesc *desc = syntax->data; + RK_S32 syn_num = syntax->number; + RK_U32 updated = 0; + RK_S32 i; + + for (i = 0; i < syn_num; i++, desc++) { + switch (desc->type) { + case H264E_SYN_CFG : { + hal_h264e_dbg_detail("update cfg"); + ctx->cfg = desc->p; + } break; + case H264E_SYN_SPS : { + hal_h264e_dbg_detail("update sps"); + ctx->sps = desc->p; + } break; + case H264E_SYN_PPS : { + hal_h264e_dbg_detail("update pps"); + ctx->pps = desc->p; + } break; + case H264E_SYN_SLICE : { + hal_h264e_dbg_detail("update slice"); + ctx->slice = desc->p; + } break; + case H264E_SYN_FRAME : { + hal_h264e_dbg_detail("update frames"); + ctx->frms = desc->p; + } break; + case H264E_SYN_RC : { + hal_h264e_dbg_detail("update rc"); + ctx->rc_syn = desc->p; + } break; + case H264E_SYN_ROI : + case H264E_SYN_OSD : + default : { + mpp_log_f("invalid syntax type %d\n", desc->type); + } break; + } + + updated |= SYN_TYPE_FLAG(desc->type); + } + + return updated; +} + +static MPP_RET hal_h264e_vepu2_get_task_v2(void *hal, HalEncTask *task) +{ + HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal; + RK_U32 updated = update_vepu2_syntax(ctx, &task->syntax); + MppEncPrepCfg *prep = &ctx->cfg->prep; + HalH264eVepuPrep *hw_prep = &ctx->hw_prep; + HalH264eVepuAddr *hw_addr = &ctx->hw_addr; + HalH264eVepuBufs *hw_bufs = &ctx->hw_bufs; + H264eFrmInfo *frms = ctx->frms; + + hal_h264e_dbg_func("enter %p\n", hal); + + if (updated & SYN_TYPE_FLAG(H264E_SYN_CFG)) { + h264e_vepu_buf_set_frame_size(hw_bufs, prep->width, prep->height); + + /* preprocess setup */ + h264e_vepu_prep_setup(hw_prep, prep); + + h264e_vepu_mbrc_setup(ctx->rc_ctx, ctx->cfg); + } + + if (updated & SYN_TYPE_FLAG(H264E_SYN_SLICE)) { + H264eSlice *slice = ctx->slice; + + h264e_vepu_buf_set_cabac_idc(hw_bufs, slice->cabac_init_idc); + } + + h264e_vepu_prep_get_addr(hw_prep, task->input, &hw_addr->orig); + + MppBuffer recn = h264e_vepu_buf_get_frame_buffer(hw_bufs, frms->curr_idx); + MppBuffer refr = h264e_vepu_buf_get_frame_buffer(hw_bufs, frms->refr_idx); + EncFrmStatus info = frms->status; + size_t yuv_size = hw_bufs->yuv_size; + + hw_addr->recn[0] = mpp_buffer_get_fd(recn); + hw_addr->refr[0] = mpp_buffer_get_fd(refr); + hw_addr->recn[1] = hw_addr->recn[0] + (yuv_size << 10); + hw_addr->refr[1] = hw_addr->refr[0] + (yuv_size << 10); + + // update input rc cfg + ctx->hal_rc_cfg = frms->rc_cfg; + + // prepare mb rc config + h264e_vepu_mbrc_prepare(ctx->rc_ctx, ctx->rc_syn, &info, &ctx->hw_mbrc); + + hal_h264e_dbg_func("leave %p\n", hal); + + return MPP_OK; +} + +static MPP_RET hal_h264e_vepu2_gen_regs_v2(void *hal, HalEncTask *task) +{ + //MPP_RET ret = MPP_OK; + HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal; + HalH264eVepuBufs *hw_bufs = &ctx->hw_bufs; + HalH264eVepuPrep *hw_prep = &ctx->hw_prep; + HalH264eVepuAddr *hw_addr = &ctx->hw_addr; + HalH264eVepuMbRc *hw_mbrc = &ctx->hw_mbrc; + SynH264eSps *sps = ctx->sps; + SynH264ePps *pps = ctx->pps; + H264eSlice *slice = ctx->slice; + RK_U32 *reg = ctx->regs_set.val; + RK_U32 mb_w = ctx->sps->pic_width_in_mbs; + RK_U32 mb_h = ctx->sps->pic_height_in_mbs; + RK_U32 val = 0; + RK_S32 i = 0; + + // TODO: Fix QP here for debug + hw_mbrc->qp_init = 26; + hw_mbrc->qp_max = 26; + hw_mbrc->qp_min = 26; + + hal_h264e_dbg_func("enter %p\n", hal); + + hal_h264e_dbg_detail("frame %d generate regs now", ctx->frms->seq_idx); + + /* output buffer size is 64 bit address then 8 multiple size */ + val = mpp_buffer_get_size(task->output); + val >>= 3; + val &= ~7; + H264E_HAL_SET_REG(reg, VEPU_REG_STR_BUF_LIMIT, val); + + /* + * The hardware needs only the value for luma plane, because + * values of other planes are calculated internally based on + * format setting. + */ + val = VEPU_REG_INTRA_AREA_TOP(mb_h) + | VEPU_REG_INTRA_AREA_BOTTOM(mb_h) + | VEPU_REG_INTRA_AREA_LEFT(mb_w) + | VEPU_REG_INTRA_AREA_RIGHT(mb_w); + H264E_HAL_SET_REG(reg, VEPU_REG_INTRA_AREA_CTRL, val); + H264E_HAL_SET_REG(reg, VEPU_REG_STR_HDR_REM_MSB, 0); + H264E_HAL_SET_REG(reg, VEPU_REG_STR_HDR_REM_LSB, 0); + + val = VEPU_REG_AXI_CTRL_READ_ID(0); + val |= VEPU_REG_AXI_CTRL_WRITE_ID(0); + val |= VEPU_REG_AXI_CTRL_BURST_LEN(16); + val |= VEPU_REG_AXI_CTRL_INCREMENT_MODE(0); + val |= VEPU_REG_AXI_CTRL_BIRST_DISCARD(0); + H264E_HAL_SET_REG(reg, VEPU_REG_AXI_CTRL, val); + + H264E_HAL_SET_REG(reg, VEPU_QP_ADJUST_MAD_DELTA_ROI, + hw_mbrc->mad_qp_change); + + val = 0; + if (mb_w * mb_h > 3600) + val = VEPU_REG_DISABLE_QUARTER_PIXEL_MV; + val |= VEPU_REG_CABAC_INIT_IDC(slice->cabac_init_idc); + if (pps->entropy_coding_mode) + val |= VEPU_REG_ENTROPY_CODING_MODE; + if (pps->transform_8x8_mode) + val |= VEPU_REG_H264_TRANS8X8_MODE; + if (sps->profile_idc > 31) + val |= VEPU_REG_H264_INTER4X4_MODE; + /*reg |= VEPU_REG_H264_STREAM_MODE;*/ + val |= VEPU_REG_H264_SLICE_SIZE(hw_mbrc->slice_size_mb_rows); + H264E_HAL_SET_REG(reg, VEPU_REG_ENC_CTRL0, val); + + RK_U32 scaler = MPP_MAX(1, 200 / (mb_w + mb_h)); + + RK_U32 skip_penalty = MPP_MIN(255, h264_skip_sad_penalty[hw_mbrc->qp_init] * scaler); + RK_U32 overfill_r = (hw_prep->src_w & 0x0f) ? + ((16 - (hw_prep->src_w & 0x0f)) / 4) : 0; + RK_U32 overfill_b = (hw_prep->src_h & 0x0f) ? + (16 - (hw_prep->src_h & 0x0f)) : 0; + + val = VEPU_REG_STREAM_START_OFFSET(0) | /* first_free_bit */ + VEPU_REG_SKIP_MACROBLOCK_PENALTY(skip_penalty) | + VEPU_REG_IN_IMG_CTRL_OVRFLR_D4(overfill_r) | + VEPU_REG_IN_IMG_CTRL_OVRFLB(overfill_b); + H264E_HAL_SET_REG(reg, VEPU_REG_ENC_OVER_FILL_STRM_OFFSET, val); + + // When offset is zero row length should be total 16 aligned width + val = VEPU_REG_IN_IMG_CHROMA_OFFSET(0) + | VEPU_REG_IN_IMG_LUMA_OFFSET(0) + | VEPU_REG_IN_IMG_CTRL_ROW_LEN(mb_w * 16); + H264E_HAL_SET_REG(reg, VEPU_REG_INPUT_LUMA_INFO, val); + + val = VEPU_REG_CHECKPOINT_CHECK1(hw_mbrc->cp_target[0]) + | VEPU_REG_CHECKPOINT_CHECK0(hw_mbrc->cp_target[1]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHECKPOINT(0), val); + + val = VEPU_REG_CHECKPOINT_CHECK1(hw_mbrc->cp_target[2]) + | VEPU_REG_CHECKPOINT_CHECK0(hw_mbrc->cp_target[3]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHECKPOINT(1), val); + + val = VEPU_REG_CHECKPOINT_CHECK1(hw_mbrc->cp_target[4]) + | VEPU_REG_CHECKPOINT_CHECK0(hw_mbrc->cp_target[5]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHECKPOINT(2), val); + + val = VEPU_REG_CHECKPOINT_CHECK1(hw_mbrc->cp_target[6]) + | VEPU_REG_CHECKPOINT_CHECK0(hw_mbrc->cp_target[7]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHECKPOINT(3), val); + + val = VEPU_REG_CHECKPOINT_CHECK1(hw_mbrc->cp_target[8]) + | VEPU_REG_CHECKPOINT_CHECK0(hw_mbrc->cp_target[9]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHECKPOINT(4), val); + + val = VEPU_REG_CHKPT_WORD_ERR_CHK1(hw_mbrc->cp_error[0]) + | VEPU_REG_CHKPT_WORD_ERR_CHK0(hw_mbrc->cp_error[1]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHKPT_WORD_ERR(0), val); + + val = VEPU_REG_CHKPT_WORD_ERR_CHK1(hw_mbrc->cp_error[2]) + | VEPU_REG_CHKPT_WORD_ERR_CHK0(hw_mbrc->cp_error[3]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHKPT_WORD_ERR(1), val); + + val = VEPU_REG_CHKPT_WORD_ERR_CHK1(hw_mbrc->cp_error[4]) + | VEPU_REG_CHKPT_WORD_ERR_CHK0(hw_mbrc->cp_error[5]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHKPT_WORD_ERR(2), val); + + val = VEPU_REG_CHKPT_DELTA_QP_CHK6(hw_mbrc->cp_delta_qp[6]) + | VEPU_REG_CHKPT_DELTA_QP_CHK5(hw_mbrc->cp_delta_qp[5]) + | VEPU_REG_CHKPT_DELTA_QP_CHK4(hw_mbrc->cp_delta_qp[4]) + | VEPU_REG_CHKPT_DELTA_QP_CHK3(hw_mbrc->cp_delta_qp[3]) + | VEPU_REG_CHKPT_DELTA_QP_CHK2(hw_mbrc->cp_delta_qp[2]) + | VEPU_REG_CHKPT_DELTA_QP_CHK1(hw_mbrc->cp_delta_qp[1]) + | VEPU_REG_CHKPT_DELTA_QP_CHK0(hw_mbrc->cp_delta_qp[0]); + H264E_HAL_SET_REG(reg, VEPU_REG_CHKPT_DELTA_QP, val); + + val = VEPU_REG_MAD_THRESHOLD(hw_mbrc->mad_threshold) + | VEPU_REG_IN_IMG_CTRL_FMT(hw_prep->src_fmt) + | VEPU_REG_IN_IMG_ROTATE_MODE(0) + | VEPU_REG_SIZE_TABLE_PRESENT; //FIXED + H264E_HAL_SET_REG(reg, VEPU_REG_ENC_CTRL1, val); + + val = VEPU_REG_INTRA16X16_MODE(h264_intra16_favor[hw_mbrc->qp_init]) + | VEPU_REG_INTER_MODE(h264_inter_favor[hw_mbrc->qp_init]); + H264E_HAL_SET_REG(reg, VEPU_REG_INTRA_INTER_MODE, val); + + val = VEPU_REG_PPS_INIT_QP(pps->pic_init_qp) + | VEPU_REG_SLICE_FILTER_ALPHA(slice->slice_alpha_c0_offset_div2) + | VEPU_REG_SLICE_FILTER_BETA(slice->slice_beta_offset_div2) + | VEPU_REG_CHROMA_QP_OFFSET(pps->chroma_qp_index_offset) + | VEPU_REG_IDR_PIC_ID(slice->idr_pic_id); + + if (slice->disable_deblocking_filter_idc) + val |= VEPU_REG_FILTER_DISABLE; + + if (pps->constrained_intra_pred) + val |= VEPU_REG_CONSTRAINED_INTRA_PREDICTION; + H264E_HAL_SET_REG(reg, VEPU_REG_ENC_CTRL2, val); + + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_NEXT_PIC, 0); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_MV_OUT, 0); + + MppBuffer cabac_table = hw_bufs->cabac_table; + RK_S32 cabac_table_fd = cabac_table ? mpp_buffer_get_fd(cabac_table) : 0; + + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_CABAC_TBL, cabac_table_fd); + + val = VEPU_REG_ROI1_TOP_MB(mb_h) + | VEPU_REG_ROI1_BOTTOM_MB(mb_h) + | VEPU_REG_ROI1_LEFT_MB(mb_w) + | VEPU_REG_ROI1_RIGHT_MB(mb_w); + H264E_HAL_SET_REG(reg, VEPU_REG_ROI1, val); + + val = VEPU_REG_ROI2_TOP_MB(mb_h) + | VEPU_REG_ROI2_BOTTOM_MB(mb_h) + | VEPU_REG_ROI2_LEFT_MB(mb_w) + | VEPU_REG_ROI2_RIGHT_MB(mb_w); + H264E_HAL_SET_REG(reg, VEPU_REG_ROI2, val); + H264E_HAL_SET_REG(reg, VEPU_REG_STABLILIZATION_OUTPUT, 0); + + val = VEPU_REG_RGB2YUV_CONVERSION_COEFB(hw_prep->color_conversion_coeff_b) + | VEPU_REG_RGB2YUV_CONVERSION_COEFA(hw_prep->color_conversion_coeff_a); + H264E_HAL_SET_REG(reg, VEPU_REG_RGB2YUV_CONVERSION_COEF1, val); + + val = VEPU_REG_RGB2YUV_CONVERSION_COEFE(hw_prep->color_conversion_coeff_e) + | VEPU_REG_RGB2YUV_CONVERSION_COEFC(hw_prep->color_conversion_coeff_c); + H264E_HAL_SET_REG(reg, VEPU_REG_RGB2YUV_CONVERSION_COEF2, val); + + val = VEPU_REG_RGB2YUV_CONVERSION_COEFF(hw_prep->color_conversion_coeff_f); + H264E_HAL_SET_REG(reg, VEPU_REG_RGB2YUV_CONVERSION_COEF3, val); + + val = VEPU_REG_RGB_MASK_B_MSB(hw_prep->b_mask_msb) + | VEPU_REG_RGB_MASK_G_MSB(hw_prep->g_mask_msb) + | VEPU_REG_RGB_MASK_R_MSB(hw_prep->r_mask_msb); + H264E_HAL_SET_REG(reg, VEPU_REG_RGB_MASK_MSB, val); //FIXED + + { + RK_U32 diff_mv_penalty[3] = {0}; + diff_mv_penalty[0] = h264_diff_mv_penalty4p[hw_mbrc->qp_init]; + diff_mv_penalty[1] = h264_diff_mv_penalty[hw_mbrc->qp_init]; + diff_mv_penalty[2] = h264_diff_mv_penalty[hw_mbrc->qp_init]; + + val = VEPU_REG_1MV_PENALTY(diff_mv_penalty[1]) + | VEPU_REG_QMV_PENALTY(diff_mv_penalty[2]) + | VEPU_REG_4MV_PENALTY(diff_mv_penalty[0]); + } + + val |= VEPU_REG_SPLIT_MV_MODE_EN; + H264E_HAL_SET_REG(reg, VEPU_REG_MV_PENALTY, val); + + val = VEPU_REG_H264_LUMA_INIT_QP(hw_mbrc->qp_init) + | VEPU_REG_H264_QP_MAX(hw_mbrc->qp_max) + | VEPU_REG_H264_QP_MIN(hw_mbrc->qp_min) + | VEPU_REG_H264_CHKPT_DISTANCE(hw_mbrc->cp_distance_mbs); + H264E_HAL_SET_REG(reg, VEPU_REG_QP_VAL, val); + + val = VEPU_REG_ZERO_MV_FAVOR_D2(10); + H264E_HAL_SET_REG(reg, VEPU_REG_MVC_RELATE, val); + + if (hw_prep->src_fmt < H264E_VPU_CSP_RGB565) { + val = VEPU_REG_OUTPUT_SWAP32 + | VEPU_REG_OUTPUT_SWAP16 + | VEPU_REG_OUTPUT_SWAP8 + | VEPU_REG_INPUT_SWAP8 + | VEPU_REG_INPUT_SWAP16 + | VEPU_REG_INPUT_SWAP32; + } else if (hw_prep->src_fmt == H264E_VPU_CSP_ARGB8888) { + val = VEPU_REG_OUTPUT_SWAP32 + | VEPU_REG_OUTPUT_SWAP16 + | VEPU_REG_OUTPUT_SWAP8 + | VEPU_REG_INPUT_SWAP32; + } else { + val = VEPU_REG_OUTPUT_SWAP32 + | VEPU_REG_OUTPUT_SWAP16 + | VEPU_REG_OUTPUT_SWAP8 + | VEPU_REG_INPUT_SWAP16 + | VEPU_REG_INPUT_SWAP32; + } + H264E_HAL_SET_REG(reg, VEPU_REG_DATA_ENDIAN, val); + + val = VEPU_REG_PPS_ID(pps->pps_id) + | VEPU_REG_INTRA_PRED_MODE(h264_prev_mode_favor[hw_mbrc->qp_init]) + | VEPU_REG_FRAME_NUM(slice->frame_num); + H264E_HAL_SET_REG(reg, VEPU_REG_ENC_CTRL3, val); + + val = VEPU_REG_INTERRUPT_TIMEOUT_EN; + H264E_HAL_SET_REG(reg, VEPU_REG_INTERRUPT, val); + + { + RK_U8 dmv_penalty[128] = {0}; + RK_U8 dmv_qpel_penalty[128] = {0}; + + for (i = 0; i < 128; i++) { + dmv_penalty[i] = i; + dmv_qpel_penalty[i] = MPP_MIN(255, exp_golomb_signed(i)); + } + + for (i = 0; i < 128; i += 4) { + val = VEPU_REG_DMV_PENALTY_TABLE_BIT(dmv_penalty[i], 3); + val |= VEPU_REG_DMV_PENALTY_TABLE_BIT(dmv_penalty[i + 1], 2); + val |= VEPU_REG_DMV_PENALTY_TABLE_BIT(dmv_penalty[i + 2], 1); + val |= VEPU_REG_DMV_PENALTY_TABLE_BIT(dmv_penalty[i + 3], 0); + H264E_HAL_SET_REG(reg, VEPU_REG_DMV_PENALTY_TBL(i / 4), val); + + val = VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT( + dmv_qpel_penalty[i], 3); + val |= VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT( + dmv_qpel_penalty[i + 1], 2); + val |= VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT( + dmv_qpel_penalty[i + 2], 1); + val |= VEPU_REG_DMV_Q_PIXEL_PENALTY_TABLE_BIT( + dmv_qpel_penalty[i + 3], 0); + H264E_HAL_SET_REG(reg, VEPU_REG_DMV_Q_PIXEL_PENALTY_TBL(i / 4), val); + } + } + + /* set buffers addr */ + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_IN_LUMA, hw_addr->orig[0]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_IN_CB, hw_addr->orig[1]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_IN_CR, hw_addr->orig[2]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_OUTPUT_STREAM, + mpp_buffer_get_fd(task->output)); + + MppBuffer nal_size_table = h264e_vepu_buf_get_nal_size_table(hw_bufs); + RK_S32 nal_size_table_fd = nal_size_table ? mpp_buffer_get_fd(nal_size_table) : 0; + + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_OUTPUT_CTRL, nal_size_table_fd); + + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_REC_LUMA, hw_addr->recn[0]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_REC_CHROMA, hw_addr->recn[1]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_REF_LUMA, hw_addr->refr[0]); + H264E_HAL_SET_REG(reg, VEPU_REG_ADDR_REF_CHROMA, hw_addr->refr[1]); + + /* set important encode mode info */ + val = VEPU_REG_MB_HEIGHT(mb_h) + | VEPU_REG_MB_WIDTH(mb_w) + | VEPU_REG_PIC_TYPE(slice->idr_flag) + | VEPU_REG_ENCODE_FORMAT(3) + | VEPU_REG_ENCODE_ENABLE; + H264E_HAL_SET_REG(reg, VEPU_REG_ENCODE_START, val); + + ctx->frame_cnt++; + + hal_h264e_dbg_func("leave %p\n", hal); + return MPP_OK; +} + +static MPP_RET hal_h264e_vepu2_start_v2(void *hal, HalEncTask *task) +{ + MPP_RET ret = MPP_OK; + HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal; + (void)task; + + hal_h264e_dbg_func("enter %p\n", hal); + + if (ctx->dev_ctx) { + RK_U32 *regs = ctx->regs_set.val; + + hal_h264e_dbg_detail("vpu client is sending %d regs", VEPU2_H264E_NUM_REGS); + ret = mpp_device_send_reg(ctx->dev_ctx, regs, VEPU2_H264E_NUM_REGS); + if (ret) + mpp_err("mpp_device_send_reg failed ret %d", ret); + else + hal_h264e_dbg_detail("mpp_device_send_reg success!"); + } else { + mpp_err("invalid device ctx: %p", ctx->dev_ctx); + ret = MPP_NOK; + } + + hal_h264e_dbg_func("leave %p\n", hal); + + return ret; +} + +static void h264e_vepu2_get_mbrc(HalH264eVepuMbRc *mb_rc, H264eVpu2RegSet *reg) +{ + RK_S32 i = 0; + RK_U32 cpt_prev = 0; + RK_U32 overflow = 0; + RK_U32 cpt_idx = VEPU_REG_CHECKPOINT(0) / 4; + RK_U32 *reg_val = reg->val; + + mb_rc->hw_status = reg_val[VEPU_REG_INTERRUPT / 4]; + mb_rc->out_strm_size = reg_val[VEPU_REG_STR_BUF_LIMIT / 4] / 8; + mb_rc->qp_sum = ((reg_val[VEPU_REG_QP_SUM_DIV2 / 4] >> 11) & 0x001fffff) * 2; + mb_rc->less_mad_count = (reg_val[VEPU_REG_MB_CTRL / 4] >> 16) & 0xffff; + mb_rc->rlc_count = reg_val[VEPU_REG_RLC_SUM / 4] & 0x3fffff; + + for (i = 0; i < CHECK_POINTS_MAX; i++) { + RK_U32 cpt = VEPU_REG_CHECKPOINT_RESULT(reg_val[cpt_idx]); + + if (cpt < cpt_prev) + overflow += (1 << 21); + + cpt_prev = cpt; + mb_rc->cp_usage[i] = cpt + overflow; + cpt_idx += (i & 1); + } +} + +static MPP_RET hal_h264e_vepu2_wait_v2(void *hal, HalEncTask *task) +{ + HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal; + HalH264eVepuMbRc *hw_mbrc = &ctx->hw_mbrc; + RK_U32 *regs_get = ctx->regs_get.val; + (void) task; + + hal_h264e_dbg_func("enter %p\n", hal); + + if (ctx->dev_ctx) { + RK_S32 hw_ret = mpp_device_wait_reg(ctx->dev_ctx, (RK_U32 *)regs_get, + VEPU2_H264E_NUM_REGS); + + hal_h264e_dbg_detail("mpp_device_wait_reg: ret %d\n", hw_ret); + + if (hw_ret != MPP_OK) { + mpp_err("hardware returns error:%d", hw_ret); + return MPP_ERR_VPUHW; + } + } else { + mpp_err("invalid device ctx: %p", ctx->dev_ctx); + return MPP_NOK; + } + + h264e_vepu2_get_mbrc(hw_mbrc, &ctx->regs_get); + + h264e_vepu_mbrc_update(ctx->rc_ctx, hw_mbrc); + + /* On TSVC case modify AVC stream to TSVC stream */ + MppEncCfgSet *cfg = ctx->cfg; + H264eSlice *slice = ctx->slice; + MppEncGopRef *ref = &cfg->gop_ref; + MppEncH264Cfg *h264 = &cfg->codec.h264; + + if (h264->svc || ref->gop_cfg_enable) { + H264eSlice hw_slice; + MppBuffer buf = task->output; + RK_U8 *p = mpp_buffer_get_ptr(buf); + RK_U32 len = hw_mbrc->out_strm_size; + RK_S32 size = mpp_buffer_get_size(buf); + RK_S32 hw_len_bit = 0; + RK_S32 sw_len_bit = 0; + RK_S32 hw_len_byte = 0; + RK_S32 sw_len_byte = 0; + RK_S32 diff_size = 0; + RK_S32 tail_0bit = 0; + RK_U8 tail_byte = 0; + RK_U8 tail_tmp = 0; + RK_U8 *dst_buf = NULL; + RK_S32 buf_size; + RK_S32 prefix_bit = 0; + RK_S32 prefix_byte = 0; + RK_S32 more_buf = 0; + + while (len > ctx->buf_size - 16) { + ctx->buf_size *= 2; + more_buf = 1; + } + + if (more_buf) { + MPP_FREE(ctx->src_buf); + MPP_FREE(ctx->dst_buf); + ctx->src_buf = mpp_malloc(RK_U8, ctx->buf_size); + ctx->dst_buf = mpp_malloc(RK_U8, ctx->buf_size); + } + + memset(ctx->dst_buf, 0, ctx->buf_size); + dst_buf = ctx->dst_buf; + buf_size = ctx->buf_size; + + // copy hw stream to stream buffer first + memcpy(ctx->src_buf, p, len); + + // prepare hw_slice with some current setup + memcpy(&hw_slice, slice, sizeof(hw_slice)); + // set hw_slice to vepu2 default hardware config + hw_slice.max_num_ref_frames = 1; + hw_slice.pic_order_cnt_type = 2; + hw_slice.log2_max_frame_num = 16; + hw_slice.log2_max_poc_lsb = 16; + + hw_len_bit = h264e_slice_read(&hw_slice, ctx->src_buf, size); + + if (h264->svc) { + H264ePrefixNal prefix; + + prefix.idr_flag = slice->idr_flag; + prefix.nal_ref_idc = slice->nal_reference_idc; + prefix.priority_id = 0; + prefix.no_inter_layer_pred_flag = 1; + prefix.dependency_id = 0; + prefix.quality_id = 0; + prefix.temporal_id = task->temporal_id; + prefix.use_ref_base_pic_flag = 0; + prefix.discardable_flag = 0; + prefix.output_flag = 1; + + prefix_bit = h264e_slice_write_prefix_nal_unit_svc(&prefix, dst_buf, buf_size); + prefix_byte = prefix_bit /= 8; + h264e_dbg_slice("prefix_len %d\n", prefix_byte); + dst_buf += prefix_byte; + buf_size -= prefix_byte; + } + + // write new header to header buffer + sw_len_bit = h264e_slice_write(slice, dst_buf, buf_size); + + h264e_slice_read(slice, dst_buf, size); + + hw_len_byte = (hw_len_bit + 7) / 8; + sw_len_byte = (sw_len_bit + 7) / 8; + + tail_byte = ctx->src_buf[len - 1]; + tail_tmp = tail_byte; + + while (!(tail_tmp & 1) && tail_0bit < 8) { + tail_tmp >>= 1; + tail_0bit++; + } + h264e_dbg_slice("tail_byte %02x bit %d\n", tail_byte, tail_0bit); + + mpp_assert(tail_0bit < 8); + + // move the reset slice data from src buffer to dst buffer + diff_size = h264e_slice_move(dst_buf, ctx->src_buf, + sw_len_bit, hw_len_bit, len); + + h264e_dbg_slice("tail 0x%02x %d hw_len_bit %d sw_len_bit %d len %d hw_len_byte %d sw_len_byte %d diff %d\n", + tail_byte, tail_0bit, hw_len_bit, sw_len_bit, len, hw_len_byte, sw_len_byte, diff_size); + + if (slice->entropy_coding_mode) { + memcpy(dst_buf + sw_len_byte, ctx->src_buf + hw_len_byte, + len - hw_len_byte); + + len += prefix_byte; + + memcpy(p, ctx->dst_buf, len - hw_len_byte + sw_len_byte); + + // clear the tail data + if (sw_len_byte < hw_len_byte) + memset(p + len - hw_len_byte + sw_len_byte, 0, hw_len_byte - sw_len_byte); + + len = len - hw_len_byte + sw_len_byte; + } else { + RK_S32 hdr_diff_bit = sw_len_bit - hw_len_bit; + RK_S32 bit_len = len * 8 - tail_0bit + hdr_diff_bit; + RK_S32 new_len = (bit_len + diff_size * 8 + 7) / 8; + + dst_buf[new_len] = 0; + + h264e_dbg_slice("frm %d len %d bit hw %d sw %d byte hw %d sw %d diff %d -> %d\n", + ctx->frms->seq_idx, len, hw_len_bit, sw_len_bit, + hw_len_byte, sw_len_byte, diff_size, new_len); + new_len += prefix_byte; + memcpy(p, ctx->dst_buf, new_len); + p[new_len] = 0; + len = new_len; + } + + hw_mbrc->out_strm_size = len; + } + + hal_h264e_dbg_func("leave %p\n", hal); + + return MPP_OK; +} + +static MPP_RET hal_h264e_vepu2_ret_task_v2(void *hal, HalEncTask *task) +{ + HalH264eVepu2Ctx *ctx = (HalH264eVepu2Ctx *)hal; + RK_U32 mb_w = ctx->sps->pic_width_in_mbs; + RK_U32 mb_h = ctx->sps->pic_height_in_mbs; + RK_U32 mbs = mb_w * mb_h; + + hal_h264e_dbg_func("enter %p\n", hal); + + task->length = ctx->hw_mbrc.out_strm_size; + + ctx->hal_rc_cfg.bit_real = task->length; + ctx->hal_rc_cfg.quality_real = ctx->hw_mbrc.qp_sum / mbs; + + task->hal_ret.data = &ctx->hal_rc_cfg; + task->hal_ret.number = 1; + + hal_h264e_dbg_func("leave %p\n", hal); + + return MPP_OK; +} + +const MppEncHalApi hal_h264e_vepu2 = { + .name = "hal_h264e_vepu2", + .coding = MPP_VIDEO_CodingAVC, + .ctx_size = sizeof(HalH264eVepu2Ctx), + .flag = 0, + .init = hal_h264e_vepu2_init_v2, + .deinit = hal_h264e_vepu2_deinit_v2, + .get_task = hal_h264e_vepu2_get_task_v2, + .gen_regs = hal_h264e_vepu2_gen_regs_v2, + .start = hal_h264e_vepu2_start_v2, + .wait = hal_h264e_vepu2_wait_v2, + .ret_task = hal_h264e_vepu2_ret_task_v2, +}; diff --git a/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.h b/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.h new file mode 100644 index 00000000..676521f6 --- /dev/null +++ b/mpp/hal/vpu/h264e/hal_h264e_vepu2_v2.h @@ -0,0 +1,24 @@ +/* + * Copyright 2015 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HAL_H264E_VEPU2_H__ +#define __HAL_H264E_VEPU2_H__ + +#include "mpp_enc_hal.h" + +extern const MppEncHalApi hal_h264e_vepu2; + +#endif diff --git a/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.c b/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.c new file mode 100644 index 00000000..e80b37b0 --- /dev/null +++ b/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.c @@ -0,0 +1,643 @@ +/* + * Copyright 2015 - 2017 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define MODULE_TAG "hal_h264e_vepu_v2" + +#include + +#include "mpp_mem.h" +#include "mpp_common.h" +#include "mpp_buffer.h" + +#include "hal_h264e_debug.h" +#include "hal_h264e_com.h" +#include "hal_h264e_vepu_v2.h" +#include "hal_h264e_vpu_tbl_v2.h" + +typedef struct HalH264eVepuMbRcImpl_t { + RK_S32 width; + RK_S32 height; + RK_S32 mb_w; + RK_S32 mb_h; + + RK_S32 pels; + RK_S32 mbs; + + RK_S32 bits_per_pic; + + RK_S32 mb_bit_rc_enable; + + /* frame rate control */ + RK_S32 fps_in_num; + RK_S32 fps_in_denorm; + RK_S32 fps_out_num; + RK_S32 fps_out_denorm; + + RK_S32 fps_count; + RK_S32 fps_step; + RK_S32 fps_threshold; + + /* + * MAD based QP adjustment + * mad_qp_change [-8..7] + * mad_threshold MAD threshold div256 + */ + RK_S32 mad_qp_change; + RK_S32 mad_threshold; + + /* + * check point parameter + */ + RK_S32 check_point_count; + RK_S32 check_point_distance; + + /* estimated first I frame qp */ + RK_S32 qp_init_est; +} HalH264eVepuMbRcImpl; + +static void vepu_swap_endian(RK_U32 *buf, RK_S32 size_bytes) +{ + RK_U32 i = 0; + RK_S32 words = size_bytes / 4; + RK_U32 val, val2, tmp, tmp2; + + mpp_assert((size_bytes % 8) == 0); + + while (words > 0) { + val = buf[i]; + tmp = 0; + + tmp |= (val & 0xFF) << 24; + tmp |= (val & 0xFF00) << 8; + tmp |= (val & 0xFF0000) >> 8; + tmp |= (val & 0xFF000000) >> 24; + { + val2 = buf[i + 1]; + tmp2 = 0; + + tmp2 |= (val2 & 0xFF) << 24; + tmp2 |= (val2 & 0xFF00) << 8; + tmp2 |= (val2 & 0xFF0000) >> 8; + tmp2 |= (val2 & 0xFF000000) >> 24; + + buf[i] = tmp2; + words--; + i++; + } + buf[i] = tmp; + words--; + i++; + } +} + +static void vepu_write_cabac_table(MppBuffer buf, RK_S32 cabac_init_idc) +{ + const RK_S32(*context)[460][2]; + RK_S32 i, j, qp; + RK_U8 table[H264E_CABAC_TABLE_BUF_SIZE] = {0}; + + for (qp = 0; qp < 52; qp++) { /* All QP values */ + for (j = 0; j < 2; j++) { /* Intra/Inter */ + if (j == 0) + /*lint -e(545) */ + context = &h264_context_init_intra; + else + /*lint -e(545) */ + context = &h264_context_init[cabac_init_idc]; + + for (i = 0; i < 460; i++) { + RK_S32 m = (RK_S32)(*context)[i][0]; + RK_S32 n = (RK_S32)(*context)[i][1]; + + RK_S32 pre_ctx_state = H264E_HAL_CLIP3(((m * (RK_S32)qp) >> 4) + + n, 1, 126); + + if (pre_ctx_state <= 63) + table[qp * 464 * 2 + j * 464 + i] = + (RK_U8)((63 - pre_ctx_state) << 1); + else + table[qp * 464 * 2 + j * 464 + i] = + (RK_U8)(((pre_ctx_state - 64) << 1) | 1); + } + } + } + + vepu_swap_endian((RK_U32 *)table, H264E_CABAC_TABLE_BUF_SIZE); + mpp_buffer_write(buf, 0, table, H264E_CABAC_TABLE_BUF_SIZE); +} + +MPP_RET h264e_vepu_buf_init(HalH264eVepuBufs *bufs) +{ + MPP_RET ret = MPP_OK; + + hal_h264e_dbg_buffer("enter %p\n", bufs); + + memset(bufs, 0, sizeof(*bufs)); + + // do not create buffer on cavlc case + bufs->cabac_init_idc = -1; + ret = mpp_buffer_group_get_internal(&bufs->group, MPP_BUFFER_TYPE_ION); + if (ret) + mpp_err_f("get buffer group failed ret %d\n", ret); + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return ret; +} + +MPP_RET h264e_vepu_buf_deinit(HalH264eVepuBufs *bufs) +{ + RK_S32 i; + + hal_h264e_dbg_buffer("enter %p\n", bufs); + + if (bufs->cabac_table) + mpp_buffer_put(bufs->cabac_table); + + if (bufs->nal_size_table) + mpp_buffer_put(bufs->nal_size_table); + + for (i = 0; i < (RK_S32)MPP_ARRAY_ELEMS(bufs->frm_buf); i++) { + if (bufs->frm_buf[i]) + mpp_buffer_put(bufs->frm_buf[i]); + } + + if (bufs->group) + mpp_buffer_group_put(bufs->group); + + memset(bufs, 0, sizeof(*bufs)); + bufs->cabac_init_idc = -1; + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return MPP_OK; +} + +MPP_RET h264e_vepu_buf_set_cabac_idc(HalH264eVepuBufs *bufs, RK_S32 idc) +{ + hal_h264e_dbg_buffer("enter %p\n", bufs); + + if (idc >= 0 && !bufs->cabac_table) + mpp_buffer_get(bufs->group, &bufs->cabac_table, H264E_CABAC_TABLE_BUF_SIZE); + + if (bufs->cabac_table && idc != bufs->cabac_init_idc && idc >= 0) + vepu_write_cabac_table(bufs->cabac_table, idc); + + bufs->cabac_init_idc = idc; + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return MPP_OK; +} + +MPP_RET h264e_vepu_buf_set_frame_size(HalH264eVepuBufs *bufs, RK_S32 w, RK_S32 h) +{ + RK_S32 aligned_w = MPP_ALIGN(w, 16); + RK_S32 aligned_h = MPP_ALIGN(h, 16); + size_t yuv_size = aligned_w * aligned_h; + size_t frm_size = yuv_size * 3 / 2; + RK_S32 i; + RK_S32 cnt = (RK_S32)MPP_ARRAY_ELEMS(bufs->frm_buf); + + hal_h264e_dbg_buffer("enter %p\n", bufs); + + mpp_assert(frm_size); + + if (frm_size != bufs->frm_size) { + if (bufs->frm_size) { + /* reallocate only on larger frame size to save time */ + mpp_log("new frame size [%d:%d] require buffer %d not equal to %d\n", + w, h, frm_size, bufs->frm_size); + } + + for (i = 0; i < cnt; i++) { + if (bufs->frm_buf[i]) { + mpp_buffer_put(bufs->frm_buf[i]); + bufs->frm_buf[i] = NULL; + bufs->frm_cnt--; + } + } + } + + bufs->mb_h = aligned_h >> 4; + if (bufs->mb_h) + bufs->nal_tab_size = MPP_ALIGN((bufs->mb_h + 1) * sizeof(RK_U32), 8); + else + bufs->nal_tab_size = 0; + + bufs->yuv_size = yuv_size; + bufs->frm_size = frm_size; + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return MPP_OK; +} + +MppBuffer h264e_vepu_buf_get_nal_size_table(HalH264eVepuBufs *bufs) +{ + MppBuffer buf = bufs->nal_size_table; + + hal_h264e_dbg_buffer("enter %p\n", bufs); + + if (NULL == buf) { + mpp_buffer_get(bufs->group, &buf, bufs->nal_tab_size); + mpp_assert(buf); + bufs->nal_size_table = buf; + } + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return buf; +} + +MppBuffer h264e_vepu_buf_get_frame_buffer(HalH264eVepuBufs *bufs, RK_S32 index) +{ + MppBuffer buf = bufs->frm_buf[index]; + + hal_h264e_dbg_buffer("enter\n", bufs); + + if (NULL == buf) { + mpp_buffer_get(bufs->group, &buf, bufs->frm_size); + mpp_assert(buf); + bufs->frm_buf[index] = buf; + bufs->frm_cnt++; + } + + hal_h264e_dbg_buffer("leave %p\n", bufs); + + return buf; +} + +static H264eVpuCsp fmt_to_vepu_csp_yuv[MPP_FMT_YUV_BUTT] = { + H264E_VPU_CSP_YUV420SP, // MPP_FMT_YUV420SP /* YYYY... UV... (NV12) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV420SP_10BIT ///< Not part of ABI + H264E_VPU_CSP_NONE, // MPP_FMT_YUV422SP /* YYYY... UVUV... (NV16) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV422SP_10BIT ///< Not part of ABI + H264E_VPU_CSP_YUV420P, // MPP_FMT_YUV420P /* YYYY... U...V... (I420) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV420SP_VU /* YYYY... VUVUVU... (NV21) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV422P /* YYYY... UU...VV...(422P) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV422SP_VU /* YYYY... VUVUVU... (NV61) */ + H264E_VPU_CSP_YUYV422, // MPP_FMT_YUV422_YUYV /* YUYVYUYV... (YUY2) */ + H264E_VPU_CSP_UYVY422, // MPP_FMT_YUV422_UYVY /* UYVYUYVY... (UYVY) */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV400 /* YYYY... */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV440SP /* YYYY... UVUV... */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV411SP /* YYYY... UV... */ + H264E_VPU_CSP_NONE, // MPP_FMT_YUV444SP /* YYYY... UVUVUVUV... */ +}; + +static H264eVpuCsp fmt_to_vepu_csp_rgb[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB] = { + H264E_VPU_CSP_RGB565, // MPP_FMT_RGB565 /* 16-bit RGB */ + H264E_VPU_CSP_RGB565, // MPP_FMT_BGR565 /* 16-bit RGB */ + H264E_VPU_CSP_RGB555, // MPP_FMT_RGB555 /* 15-bit RGB */ + H264E_VPU_CSP_RGB555, // MPP_FMT_BGR555 /* 15-bit RGB */ + H264E_VPU_CSP_RGB444, // MPP_FMT_RGB444 /* 12-bit RGB */ + H264E_VPU_CSP_RGB444, // MPP_FMT_BGR444 /* 12-bit RGB */ + H264E_VPU_CSP_RGB888, // MPP_FMT_RGB888 /* 24-bit RGB */ + H264E_VPU_CSP_RGB888, // MPP_FMT_BGR888 /* 24-bit RGB */ + H264E_VPU_CSP_RGB101010, // MPP_FMT_RGB101010 /* 30-bit RGB */ + H264E_VPU_CSP_RGB101010, // MPP_FMT_BGR101010 /* 30-bit RGB */ + H264E_VPU_CSP_ARGB8888, // MPP_FMT_ARGB8888 /* 32-bit RGB */ + H264E_VPU_CSP_ARGB8888, // MPP_FMT_ABGR8888 /* 32-bit RGB */ +}; + +static RK_S32 fmt_to_vepu_mask_msb[MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB][3] = { + // R G B // mask msb position + { 15, 10, 4, }, // MPP_FMT_RGB565 /* 16-bit RGB */ + { 4, 10, 15, }, // MPP_FMT_BGR565 /* 16-bit RGB */ + { 14, 9, 4, }, // MPP_FMT_RGB555 /* 15-bit RGB */ + { 4, 9, 14, }, // MPP_FMT_BGR555 /* 15-bit RGB */ + { 11, 7, 3, }, // MPP_FMT_RGB444 /* 12-bit RGB */ + { 3, 7, 11, }, // MPP_FMT_BGR444 /* 12-bit RGB */ + { 23, 15, 7, }, // MPP_FMT_RGB888 /* 24-bit RGB */ + { 7, 15, 23, }, // MPP_FMT_BGR888 /* 24-bit RGB */ + { 29, 19, 9, }, // MPP_FMT_RGB101010 /* 30-bit RGB */ + { 9, 19, 29, }, // MPP_FMT_BGR101010 /* 30-bit RGB */ + { 23, 15, 7, }, // MPP_FMT_ARGB8888 /* 32-bit RGB */ + { 7, 15, 23, }, // MPP_FMT_ABGR8888 /* 32-bit RGB */ +}; + +MPP_RET h264e_vepu_prep_setup(HalH264eVepuPrep *prep, MppEncPrepCfg *cfg) +{ + MPP_RET ret = MPP_OK; + MppFrameFormat format = cfg->format; + + hal_h264e_dbg_buffer("enter\n"); + + prep->src_fmt = format; + prep->src_w = cfg->width; + prep->src_h = cfg->height; + + if (format < MPP_FRAME_FMT_RGB) { + // YUV case + prep->src_fmt = fmt_to_vepu_csp_yuv[format]; + if (prep->src_fmt == H264E_VPU_CSP_NONE) { + mpp_err("vepu do not support input frame format %d\n", format); + ret = MPP_NOK; + } + prep->r_mask_msb = 0; + prep->g_mask_msb = 0; + prep->b_mask_msb = 0; + + prep->color_conversion_coeff_a = 0; + prep->color_conversion_coeff_b = 0; + prep->color_conversion_coeff_c = 0; + prep->color_conversion_coeff_e = 0; + prep->color_conversion_coeff_f = 0; + } else { + // RGB case + RK_S32 rgb_idx = format - MPP_FRAME_FMT_RGB; + + mpp_assert(rgb_idx < MPP_FMT_RGB_BUTT - MPP_FRAME_FMT_RGB); + + prep->src_fmt = fmt_to_vepu_csp_rgb[rgb_idx]; + if (prep->src_fmt == H264E_VPU_CSP_NONE) { + mpp_err("vepu do not support input frame format %d\n", format); + ret = MPP_NOK; + } + prep->r_mask_msb = fmt_to_vepu_mask_msb[rgb_idx][0]; + prep->g_mask_msb = fmt_to_vepu_mask_msb[rgb_idx][1]; + prep->b_mask_msb = fmt_to_vepu_mask_msb[rgb_idx][2]; + + switch (cfg->color) { + case MPP_FRAME_SPC_RGB : { + /* BT.601 */ + /* Y = 0.2989 R + 0.5866 G + 0.1145 B + * Cb = 0.5647 (B - Y) + 128 + * Cr = 0.7132 (R - Y) + 128 + */ + prep->color_conversion_coeff_a = 19589; + prep->color_conversion_coeff_b = 38443; + prep->color_conversion_coeff_c = 7504; + prep->color_conversion_coeff_e = 37008; + prep->color_conversion_coeff_f = 46740; + } break; + case MPP_FRAME_SPC_BT709 : { + /* BT.709 */ + /* Y = 0.2126 R + 0.7152 G + 0.0722 B + * Cb = 0.5389 (B - Y) + 128 + * Cr = 0.6350 (R - Y) + 128 + */ + prep->color_conversion_coeff_a = 13933; + prep->color_conversion_coeff_b = 46871; + prep->color_conversion_coeff_c = 4732; + prep->color_conversion_coeff_e = 35317; + prep->color_conversion_coeff_f = 41615; + } break; + default : { + prep->color_conversion_coeff_a = 19589; + prep->color_conversion_coeff_b = 38443; + prep->color_conversion_coeff_c = 7504; + prep->color_conversion_coeff_e = 37008; + prep->color_conversion_coeff_f = 46740; + } break; + } + } + + RK_S32 hor_stride = cfg->hor_stride; + RK_S32 ver_stride = cfg->ver_stride; + prep->offset_cb = 0; + prep->offset_cr = 0; + + switch (format) { + case MPP_FMT_YUV420SP : { + prep->offset_cb = hor_stride * ver_stride; + prep->size_y = hor_stride * MPP_ALIGN(prep->src_h, 16); + prep->size_c = hor_stride / 2 * MPP_ALIGN(prep->src_h / 2, 8); + } break; + case MPP_FMT_YUV420P : { + prep->offset_cb = hor_stride * ver_stride; + prep->offset_cr = prep->offset_cb + ((hor_stride * ver_stride) / 4); + prep->size_y = hor_stride * MPP_ALIGN(prep->src_h, 16); + prep->size_c = hor_stride / 2 * MPP_ALIGN(prep->src_h / 2, 8); + } break; + case MPP_FMT_YUV422_YUYV : + case MPP_FMT_YUV422_UYVY : { + prep->size_y = hor_stride * 2 * MPP_ALIGN(prep->src_h, 16); + prep->size_c = 0; + } break; + case MPP_FMT_RGB565 : + case MPP_FMT_BGR444 : { + prep->size_y = hor_stride * 2 * MPP_ALIGN(prep->src_h, 16); + prep->size_c = 0; + } break; + case MPP_FMT_BGR888 : + case MPP_FMT_RGB888 : + case MPP_FMT_ARGB8888 : + case MPP_FMT_ABGR8888 : + case MPP_FMT_BGR101010 : { + prep->size_y = hor_stride * 4 * MPP_ALIGN(prep->src_h, 16); + prep->size_c = 0; + } break; + default: { + mpp_err_f("invalid format %d", format); + ret = MPP_NOK; + } + } + + hal_h264e_dbg_buffer("leave\n"); + + return ret; +} + +MPP_RET h264e_vepu_prep_get_addr(HalH264eVepuPrep *prep, MppBuffer buffer, + RK_U32 (*addr)[3]) +{ + RK_U32 fd = (RK_U32)mpp_buffer_get_fd(buffer); + size_t size = mpp_buffer_get_size(buffer); + + hal_h264e_dbg_buffer("enter\n"); + + (*addr)[0] = fd; + (*addr)[1] = fd + (prep->offset_cb << 10); + (*addr)[2] = fd + (prep->offset_cr << 10); + + if (size < prep->size_y) + mpp_err("warnning: input buffer size 0x%x is smaller then required size 0x%x", + size, prep->size_y); + + if (prep->size_c && (prep->offset_cb || prep->offset_cr)) { + if (prep->offset_cb && (size < prep->offset_cb + prep->size_c)) + mpp_err("warnning: input buffer size 0x%x is smaller then cb requirement 0x%x + 0x%x", + size, prep->offset_cb, prep->size_c); + + if (prep->offset_cr && (size < prep->offset_cr + prep->size_c)) + mpp_err("warnning: input buffer size 0x%x is smaller then cb requirement 0x%x + 0x%x", + size, prep->offset_cr, prep->size_c); + } + + hal_h264e_dbg_buffer("leave\n"); + + return MPP_OK; +} + +MPP_RET h264e_vepu_mbrc_init(HalH264eVepuMbRcCtx *ctx, HalH264eVepuMbRc *mbrc) +{ + MPP_RET ret = MPP_OK; + HalH264eVepuMbRcImpl *p = mpp_calloc(HalH264eVepuMbRcImpl, 1); + if (!p) { + mpp_err_f("failed to alloc rate control context\n"); + ret = MPP_ERR_NOMEM; + } + + memset(mbrc, 0, sizeof(*mbrc)); + mbrc->qp_init = -1; + mbrc->qp_max = 48; + mbrc->qp_min = 16; + + *ctx = p; + return ret; +} + +MPP_RET h264e_vepu_mbrc_deinit(HalH264eVepuMbRcCtx ctx) +{ + MPP_FREE(ctx); + return MPP_OK; +} + +static RK_S32 qp_tbl[2][13] = { + { + 26, 36, 48, 63, 85, 110, 152, 208, 313, 427, 936, + 1472, 0x7fffffff + }, + {42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6} +}; + +MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet*cfg) +{ + HalH264eVepuMbRcImpl *p = (HalH264eVepuMbRcImpl *)ctx; + MppEncH264Cfg *codec = &cfg->codec.h264; + MppEncPrepCfg *prep = &cfg->prep; + MppEncRcCfg *rc = &cfg->rc; + + hal_h264e_dbg_rc("enter\n"); + + // get necessary parameter from config + p->width = prep->width; + p->height = prep->height; + p->mb_w = MPP_ALIGN(prep->width, 16) / 16; + p->mb_h = MPP_ALIGN(prep->height, 16) / 16; + p->pels = p->width * p->height; + p->mbs = p->mb_w * p->mb_h; + p->bits_per_pic = axb_div_c(rc->bps_target, rc->fps_out_denorm, + rc->fps_out_num); + + mpp_assert(p->pels); + + // frame rate control + mpp_assert(rc->fps_out_num / rc->fps_out_denorm <= rc->fps_in_num / rc->fps_in_denorm); + + p->fps_in_num = rc->fps_in_num; + p->fps_in_denorm = rc->fps_in_denorm; + p->fps_out_num = rc->fps_out_num; + p->fps_out_denorm = rc->fps_out_denorm; + + p->fps_step = rc->fps_in_denorm * rc->fps_out_num; + p->fps_threshold = rc->fps_in_num * rc->fps_out_denorm; + p->fps_count = p->fps_threshold; + + // if not constant + p->mb_bit_rc_enable = !(rc->rc_mode == MPP_ENC_RC_MODE_VBR && + rc->quality == MPP_ENC_RC_QUALITY_CQP); + + // init first frame QP + if (p->bits_per_pic > 1000000) + p->qp_init_est = codec->qp_min; + else { + RK_S32 upscale = 8000; + RK_S32 i = -1; + RK_S32 bits_per_pic = p->bits_per_pic; + RK_S32 mbs = p->mbs; + + bits_per_pic >>= 5; + + bits_per_pic *= mbs + 250; + bits_per_pic /= 350 + (3 * mbs) / 4; + bits_per_pic = axb_div_c(bits_per_pic, upscale, mbs << 6); + + while (qp_tbl[0][++i] < bits_per_pic); + + p->qp_init_est = qp_tbl[1][i]; + } + hal_h264e_dbg_rc("estimated init qp %d\n", p->qp_init_est); + + // init first frame mad parameter + p->mad_qp_change = 2; + p->mad_threshold = 256 * 6; + + // init check point position + if (p->mb_bit_rc_enable) { + p->check_point_count = MPP_MIN(p->mb_h - 1, CHECK_POINTS_MAX); + p->check_point_distance = p->mbs / (p->check_point_count + 1); + } else { + p->check_point_count = 0; + p->check_point_distance = 0; + } + + hal_h264e_dbg_rc("leave\n"); + return MPP_OK; +} + +MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, RcSyntax *rc, + EncFrmStatus *info, HalH264eVepuMbRc *mbrc) +{ + HalH264eVepuMbRcImpl *p = (HalH264eVepuMbRcImpl *)ctx; + RK_S32 target_bits = rc->bit_target; + RK_S32 target_step = target_bits / (p->check_point_count + 1); + RK_S32 target_sum = 0; + RK_S32 tmp; + RK_S32 i; + + mpp_assert(target_step >= 0); + (void) info; + + for (i = 0; i < VEPU_CHECK_POINTS_MAX; i++) { + target_sum += target_step; + mbrc->cp_target[i] = mpp_clip(target_sum / 32, -32768, 32767); + } + + tmp = target_step / 8; + + mbrc->cp_error[0] = -tmp * 3; + mbrc->cp_delta_qp[0] = -3; + mbrc->cp_error[1] = -tmp * 2; + mbrc->cp_delta_qp[1] = -2; + mbrc->cp_error[2] = -tmp * 1; + mbrc->cp_delta_qp[2] = -1; + mbrc->cp_error[3] = tmp * 1; + mbrc->cp_delta_qp[3] = 0; + mbrc->cp_error[4] = tmp * 2; + mbrc->cp_delta_qp[4] = 1; + mbrc->cp_error[5] = tmp * 3; + mbrc->cp_delta_qp[5] = 2; + mbrc->cp_error[6] = tmp * 4; + mbrc->cp_delta_qp[6] = 3; + + mbrc->mad_qp_change = 2; + mbrc->mad_threshold = 2; + + mbrc->cp_distance_mbs = p->check_point_distance; + return MPP_OK; +} + +MPP_RET h264e_vepu_mbrc_update(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc) +{ + HalH264eVepuMbRcImpl *p = (HalH264eVepuMbRcImpl *)ctx; + (void) p; + (void) mbrc; + + hal_h264e_dbg_rc("enter\n"); + hal_h264e_dbg_rc("leave\n"); + return MPP_OK; +} diff --git a/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.h b/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.h new file mode 100644 index 00000000..59f5f81a --- /dev/null +++ b/mpp/hal/vpu/h264e/hal_h264e_vepu_v2.h @@ -0,0 +1,195 @@ +/* + * Copyright 2017 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HAL_H264E_VEPU_V2_H__ +#define __HAL_H264E_VEPU_V2_H__ + +#include "mpp_enc_cfg.h" +#include "h264e_syntax_new.h" +#include "mpp_rc.h" + +typedef enum H264eVpuFrameType_t { + H264E_VPU_FRAME_P = 0, + H264E_VPU_FRAME_I = 1 +} H264eVpuFrameType; + +#define VEPU_CTRL_LEVELS 7 +#define VEPU_CHECK_POINTS_MAX 10 + +typedef struct HalH264eVepuInput_t { + /* Hardware config format */ + RK_S32 src_fmt; + RK_S32 src_w; + RK_S32 src_h; + size_t size_y; + size_t size_c; + + RK_U32 offset_cb; + RK_U32 offset_cr; + + RK_S32 r_mask_msb; + RK_S32 g_mask_msb; + RK_S32 b_mask_msb; + + RK_U32 color_conversion_coeff_a; + RK_U32 color_conversion_coeff_b; + RK_U32 color_conversion_coeff_c; + RK_U32 color_conversion_coeff_e; + RK_U32 color_conversion_coeff_f; +} HalH264eVepuPrep; + +typedef struct HalH264eVepuFrmAddr_t { + // original frame Y/Cb/Cr/RGB address + RK_U32 orig[3]; + // reconstruction frame + RK_U32 recn[2]; + RK_U32 refr[2]; +} HalH264eVepuAddr; + +/* + * Vepu buffer allocater + * There are three internal buffer for Vepu encoder: + * 1. cabac table input buffer + * 2. nal size table output buffer + * 3. recon / refer frame buffer + */ +typedef struct HalH264eVepuBufs_t { + MppBufferGroup group; + + /* cabac table buffer */ + RK_S32 cabac_init_idc; + MppBuffer cabac_table; + + /* + * nal size table buffer + * table size must be 64-bit multiple, space for zero at the end of table + * Atleast 1 macroblock row in every slice + */ + RK_S32 mb_h; + RK_S32 nal_tab_size; + MppBuffer nal_size_table; + + /* + * recon / refer frame buffer + * sync with encoder using slot index + */ + size_t frm_size; + size_t yuv_size; + RK_S32 frm_cnt; + MppBuffer frm_buf[H264E_MAX_REFS_CNT + 1]; +} HalH264eVepuBufs; + +typedef struct HalH264eVepuMbRc_t { + /* VEPU MB rate control parameter for config to hardware */ + RK_S32 qp_init; + RK_S32 qp_min; + RK_S32 qp_max; + + /* + * VEPU MB can have max 10 check points (cp). + * + * On each check point hardware will check the target bit and + * error bits and change qp according to delta qp step + * + * cp_distance_mbs check point distance in mbs (0 = disabled) + * cp_target bitrate target at each check point + * cp_error error bit level step for each delta qp + * cp_delta_qp delta qp applied on when on bit rate error amount + */ + RK_S32 cp_distance_mbs; + RK_S32 cp_target[VEPU_CHECK_POINTS_MAX]; + RK_S32 cp_error[VEPU_CTRL_LEVELS]; + RK_S32 cp_delta_qp[VEPU_CTRL_LEVELS]; + + /* + * MAD based QP adjustment + * mad_qp_change [-8..7] + * mad_threshold MAD threshold div256 + */ + RK_S32 mad_qp_change; + RK_S32 mad_threshold; + + /* slice split by mb row (0 = one slice) */ + RK_S32 slice_size_mb_rows; + + /* favor and penalty for mode decision */ + + /* + * VEPU MB rate control parameter which is read from hardware + * out_strm_size output stream size (bits) + * qp_sum QP Sum div2 output + * rlc_count RLC codeword count div4 output max 255*255*384/4 + */ + RK_U32 out_strm_size; + RK_S32 qp_sum; + RK_S32 rlc_count; + + RK_S32 cp_usage[VEPU_CHECK_POINTS_MAX]; + /* Macroblock count with MAD value under threshold output */ + RK_S32 less_mad_count; + /* MB count output */ + RK_S32 mb_count; + + /* hardware encoding status 0 - corret 1 - error */ + RK_U32 hw_status; +} HalH264eVepuMbRc; + +typedef void *HalH264eVepuMbRcCtx; + +#ifdef __cplusplus +extern "C" { +#endif + +/* buffer management function */ +MPP_RET h264e_vepu_buf_init(HalH264eVepuBufs *bufs); +MPP_RET h264e_vepu_buf_deinit(HalH264eVepuBufs *bufs); + +MPP_RET h264e_vepu_buf_set_cabac_idc(HalH264eVepuBufs *bufs, RK_S32 idc); +MPP_RET h264e_vepu_buf_set_frame_size(HalH264eVepuBufs *bufs, RK_S32 w, RK_S32 h); + +MppBuffer h264e_vepu_buf_get_nal_size_table(HalH264eVepuBufs *bufs); +MppBuffer h264e_vepu_buf_get_frame_buffer(HalH264eVepuBufs *bufs, RK_S32 index); + +/* preprocess setup function */ +MPP_RET h264e_vepu_prep_setup(HalH264eVepuPrep *prep, MppEncPrepCfg *cfg); +MPP_RET h264e_vepu_prep_get_addr(HalH264eVepuPrep *prep, MppBuffer buffer, + RK_U32 (*addr)[3]); + +/* macroblock bitrate control function */ +MPP_RET h264e_vepu_mbrc_init(HalH264eVepuMbRcCtx *ctx, HalH264eVepuMbRc *mbrc); +MPP_RET h264e_vepu_mbrc_deinit(HalH264eVepuMbRcCtx ctx); + +MPP_RET h264e_vepu_mbrc_setup(HalH264eVepuMbRcCtx ctx, MppEncCfgSet *cfg); +/* + * generate hardware MB rc config by: + * 1 - HalH264eVepuMbRcCtx ctx + * The previous frame encoding status + * 2 - RcSyntax + * Provide current frame target bitrate related info + * 3 - EncFrmStatus + * Provide dpb related info like I / P frame, temporal id, refer distance + * + * Then output the HalH264eVepuMbRc for register generation + */ +MPP_RET h264e_vepu_mbrc_prepare(HalH264eVepuMbRcCtx ctx, RcSyntax *rc, + EncFrmStatus *info, HalH264eVepuMbRc *mbrc); +MPP_RET h264e_vepu_mbrc_update(HalH264eVepuMbRcCtx ctx, HalH264eVepuMbRc *mbrc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mpp/hal/vpu/h264e/hal_h264e_vpu_tbl_v2.h b/mpp/hal/vpu/h264e/hal_h264e_vpu_tbl_v2.h new file mode 100644 index 00000000..dc87dd50 --- /dev/null +++ b/mpp/hal/vpu/h264e/hal_h264e_vpu_tbl_v2.h @@ -0,0 +1,36 @@ +/* + * Copyright 2015 Rockchip Electronics Co. LTD + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __HAL_H264E_VPU_TBL_H__ +#define __HAL_H264E_VPU_TBL_H__ + +#include "rk_type.h" + +#define H264E_CABAC_TABLE_BUF_SIZE (52*2*464) + +/* H.264 motion estimation parameters */ +extern const RK_U32 h264_prev_mode_favor[52]; +/* sqrt(2^((qp-12)/3))*8 */ +extern const RK_U32 h264_diff_mv_penalty[52]; +/* 31*sqrt(2^((qp-12)/3))/4 */ +extern const RK_U32 h264_diff_mv_penalty4p[52]; +extern const RK_U32 h264_intra16_favor[52]; +extern const RK_U32 h264_inter_favor[52]; +extern const RK_U32 h264_skip_sad_penalty[52]; +extern const RK_S32 h264_context_init_intra[460][2]; +extern const RK_S32 h264_context_init[3][460][2]; + +#endif