/* * 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. */ #define MODULE_TAG "hal_vp8e_base" #include #include "mpp_mem.h" #include "mpp_buffer.h" #include "mpp_common.h" #include "hal_vp8e_base.h" #include "hal_vp8e_putbit.h" #include "hal_vp8e_table.h" #include "hal_vp8e_debug.h" #include "vepu_common.h" static MPP_RET set_frame_params(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; { RK_S32 i; Pps *pps = ctx->ppss.pps; Vp8eSps *sps = &ctx->sps; for (i = 0; i < 4; i++) { pps->qp_sgm[i] = ctx->rc->qp_hdr; pps->level_sgm[i] = sps->filter_level; } } return MPP_OK; } static MPP_RET set_filter(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eSps *sps = &ctx->sps; if (sps->auto_filter_level) { RK_U32 qp = 36; Pps *p_pps = ctx->ppss.pps; if (ctx->frame_type == VP8E_FRM_KEY) { RK_S32 tmp = (qp * 64) / 128 + 8; sps->filter_level = MPP_CLIP3(0, 63, tmp); p_pps->level_sgm[0] = MPP_CLIP3(0, 63, (p_pps->qp_sgm[0] * 64) / 128 + 8); p_pps->level_sgm[1] = MPP_CLIP3(0, 63, (p_pps->qp_sgm[1] * 64) / 128 + 8); p_pps->level_sgm[2] = MPP_CLIP3(0, 63, (p_pps->qp_sgm[2] * 64) / 128 + 8); p_pps->level_sgm[3] = MPP_CLIP3(0, 63, (p_pps->qp_sgm[3] * 64) / 128 + 8); } else { sps->filter_level = inter_level_tbl[qp]; p_pps->level_sgm[0] = inter_level_tbl[p_pps->qp_sgm[0]]; p_pps->level_sgm[1] = inter_level_tbl[p_pps->qp_sgm[1]]; p_pps->level_sgm[2] = inter_level_tbl[p_pps->qp_sgm[2]]; p_pps->level_sgm[3] = inter_level_tbl[p_pps->qp_sgm[3]]; } } if (sps->auto_filter_sharpness) { sps->filter_sharpness = 0; } if (!sps->filter_delta_enable) return MPP_NOK; if (sps->filter_delta_enable == 2) { sps->filter_delta_enable = 1; return MPP_NOK; } if (sps->filter_level == 0) { sps->ref_delta[0] = 0; /* Intra frame */ sps->ref_delta[1] = 0; /* Last frame */ sps->ref_delta[2] = 0; /* Golden frame */ sps->ref_delta[3] = 0; /* Altref frame */ sps->mode_delta[0] = 0; /* BPRED */ sps->mode_delta[1] = 0; /* Zero */ sps->mode_delta[2] = 0; /* New mv */ sps->mode_delta[3] = 0; /* Split mv */ return MPP_NOK; } if (!ctx->picbuf.cur_pic->ipf && !ctx->picbuf.cur_pic->grf && !ctx->picbuf.cur_pic->arf) { memcpy(sps->ref_delta, sps->old_ref_delta, sizeof(sps->ref_delta)); memcpy(sps->mode_delta, sps->old_mode_delta, sizeof(sps->mode_delta)); return MPP_NOK; } sps->ref_delta[0] = 2; /* Intra frame */ sps->ref_delta[1] = 0; /* Last frame */ sps->ref_delta[2] = -2; /* Golden frame */ sps->ref_delta[3] = -2; /* Altref frame */ sps->mode_delta[0] = 4; /* BPRED */ sps->mode_delta[1] = -2; /* Zero */ sps->mode_delta[2] = 2; /* New mv */ sps->mode_delta[3] = 4; /* Split mv */ { RK_U32 i = 0; for (i = 0; i < 4; i++) { sps->ref_delta[i] = MPP_CLIP3(-0x3f, 0x3f, sps->ref_delta[i]); sps->mode_delta[i] = MPP_CLIP3(-0x3f, 0x3f, sps->mode_delta[i]); } } return MPP_OK; } static MPP_RET set_segmentation(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8ePps *ppss = &ctx->ppss; Pps *pps = ppss->pps; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; { RK_S32 qp = ctx->rc->qp_hdr; if (hw_cfg->roi1_delta_qp) pps->qp_sgm[1] = MPP_CLIP3(0, 127, qp - hw_cfg->roi1_delta_qp); if (hw_cfg->roi2_delta_qp) pps->qp_sgm[2] = MPP_CLIP3(0, 127, qp - hw_cfg->roi2_delta_qp); } { RK_U32 x, y, mb, mask, id; RK_U32 *map = mpp_buffer_get_ptr(buffers->hw_segment_map_buf); RK_U32 *map_bck = map; RK_U32 mapSize = (ctx->mb_per_frame + 15) / 16 * 8; if (hw_cfg->roi1_delta_qp || hw_cfg->roi2_delta_qp) { pps->segment_enabled = 1; memset(pps->sgm.id_cnt, 0, sizeof(pps->sgm.id_cnt)); for (y = 0, mb = 0, mask = 0; y < ctx->mb_per_col; y++) { for (x = 0; x < ctx->mb_per_row; x++) { id = 0; if ((x >= hw_cfg->roi1_left) && (x <= hw_cfg->roi1_right) && (y >= hw_cfg->roi1_top) && (y <= hw_cfg->roi1_bottom)) id = 1; if ((x >= hw_cfg->roi1_left) && (x <= hw_cfg->roi2_right) && (y >= hw_cfg->roi2_top) && (y <= hw_cfg->roi2_bottom)) id = 2; pps->sgm.id_cnt[id]++; mask |= id << (28 - 4 * (mb % 8)); if ((mb % 8) == 7) { *map++ = mask; mask = 0; } mb++; } } *map++ = mask; vp8e_swap_endian(map_bck, mapSize); } else if (pps->segment_enabled && pps->sgm.map_modified) { memset(pps->sgm.id_cnt, 0, sizeof(pps->sgm.id_cnt)); for (mb = 0, mask = 0; mb < mapSize / 4; mb++) { mask = map[mb]; for (x = 0; x < 8; x++) { if (mb * 8 + x < ctx->mb_per_frame) { id = (mask >> (28 - 4 * x)) & 0xF; pps->sgm.id_cnt[id]++; } } } vp8e_swap_endian(map_bck, mapSize); } } if (ctx->picbuf.cur_pic->i_frame || !pps->segment_enabled) { memset(ppss->qp_sgm, 0xff, sizeof(ppss->qp_sgm)); memset(ppss->level_sgm, 0xff, sizeof(ppss->level_sgm)); ppss->prev_pps = NULL; } else ppss->prev_pps = ppss->pps; return MPP_OK; } static void set_intra_pred_penalties(Vp8eHwCfg *hw_cfg, RK_U32 qp) { RK_S32 i, tmp; /* Intra 4x4 mode */ tmp = qp * 2 + 8; for (i = 0; i < 10; i++) { hw_cfg->intra_b_mode_penalty[i] = (intra4_mode_tree_penalty_tbl[i] * tmp) >> 8; } /* Intra 16x16 mode */ tmp = qp * 2 + 64; for (i = 0; i < 4; i++) { hw_cfg->intra_mode_penalty[i] = (intra16_mode_tree_penalty_tbl[i] * tmp) >> 8; } /* If favor has not been set earlier by testId use default */ if (hw_cfg->intra_16_favor == -1) hw_cfg->intra_16_favor = qp * 1024 / 128; } static void set_hdr_segmentation(Vp8ePutBitBuf *bitbuf, Vp8ePps *ppss, Vp8eHalEntropy *entropy) { RK_S32 i, tmp; RK_U8 data_modified = 0; Pps *pps = ppss->pps; Sgm *sgm = &ppss->pps->sgm; if (memcmp(ppss->qp_sgm, pps->qp_sgm, sizeof(ppss->qp_sgm))) data_modified = 1; if (memcmp(ppss->level_sgm, pps->level_sgm, sizeof(ppss->level_sgm))) data_modified = 1; if (!ppss->prev_pps) { sgm->map_modified = 1; } vp8e_put_lit(bitbuf, sgm->map_modified, 1); vp8e_put_lit(bitbuf, data_modified, 1); if (data_modified) { vp8e_put_lit(bitbuf, 1, 1); for (i = 0; i < SGM_CNT; i++) { tmp = pps->qp_sgm[i]; vp8e_put_lit(bitbuf, 1, 1); vp8e_put_lit(bitbuf, MPP_ABS(tmp), 7); vp8e_put_lit(bitbuf, tmp < 0, 1); } for (i = 0; i < SGM_CNT; i++) { tmp = pps->level_sgm[i]; vp8e_put_lit(bitbuf, 1, 1); vp8e_put_lit(bitbuf, MPP_ABS(tmp), 6); vp8e_put_lit(bitbuf, tmp < 0, 1); } } if (sgm->map_modified) { RK_S32 sum1 = sgm->id_cnt[0] + sgm->id_cnt[1]; RK_S32 sum2 = sgm->id_cnt[2] + sgm->id_cnt[3]; tmp = 255 * sum1 / (sum1 + sum2); entropy->segment_prob[0] = MPP_CLIP3(1, 255, tmp); tmp = sum1 ? 255 * sgm->id_cnt[0] / sum1 : 255; entropy->segment_prob[1] = MPP_CLIP3(1, 255, tmp); tmp = sum2 ? 255 * sgm->id_cnt[2] / sum2 : 255; entropy->segment_prob[2] = MPP_CLIP3(1, 255, tmp); for (i = 0; i < 3; i++) { if (sgm->id_cnt[i] != 0) { vp8e_put_lit(bitbuf, 1, 1); vp8e_put_lit(bitbuf, entropy->segment_prob[i], 8); } else { vp8e_put_lit(bitbuf, 0, 1); } } } memcpy(ppss->qp_sgm, pps->qp_sgm, sizeof(ppss->qp_sgm)); memcpy(ppss->level_sgm, pps->level_sgm, sizeof(ppss->level_sgm)); } static void set_filter_level_delta(Vp8ePutBitBuf *bitbuf, Vp8eSps *sps) { RK_S32 i, tmp; RK_U8 update = 0; RK_S32 mode_update[4]; RK_S32 ref_update[4]; for (i = 0; i < 4; i++) { mode_update[i] = sps->mode_delta[i] != sps->old_mode_delta[i]; ref_update[i] = sps->ref_delta[i] != sps->old_ref_delta[i]; if (mode_update[i] || ref_update[i]) update = 1; } if (!sps->refresh_entropy) update = 1; vp8e_put_lit(bitbuf, update, 1); if (!update) return; for (i = 0; i < 4; i++) { vp8e_put_lit(bitbuf, ref_update[i], 1); if (ref_update[i]) { tmp = sps->ref_delta[i]; vp8e_put_lit(bitbuf, MPP_ABS(tmp), 6); vp8e_put_lit(bitbuf, tmp < 0, 1); } } for (i = 0; i < 4; i++) { vp8e_put_lit(bitbuf, mode_update[i], 1); if (mode_update[i]) { tmp = sps->mode_delta[i]; vp8e_put_lit(bitbuf, MPP_ABS(tmp), 6); vp8e_put_lit(bitbuf, tmp < 0, 1); } } memcpy(sps->old_ref_delta, sps->ref_delta, sizeof(sps->ref_delta)); memcpy(sps->old_mode_delta, sps->mode_delta, sizeof(sps->mode_delta)); } static MPP_RET set_frame_header(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eSps *sps = &ctx->sps; Pps *pps = ctx->ppss.pps; Vp8ePutBitBuf *bitbuf = &ctx->bitbuf[1]; HalVp8eRefPic *cur_pic = ctx->picbuf.cur_pic; Vp8eHalEntropy *entropy = &ctx->entropy; if (cur_pic->i_frame) { vp8e_put_lit(bitbuf, sps->color_type, 1); vp8e_put_lit(bitbuf, sps->clamp_type, 1); } vp8e_put_lit(bitbuf, pps->segment_enabled, 1); if (pps->segment_enabled) set_hdr_segmentation(bitbuf, &ctx->ppss, entropy); vp8e_put_lit(bitbuf, sps->filter_type, 1); vp8e_put_lit(bitbuf, sps->filter_level, 6); vp8e_put_lit(bitbuf, sps->filter_sharpness, 3); vp8e_put_lit(bitbuf, sps->filter_delta_enable, 1); if (sps->filter_delta_enable) { /* Filter level delta references reset by key frame */ if (cur_pic->i_frame) { memset(sps->old_ref_delta, 0, sizeof(sps->ref_delta)); memset(sps->old_mode_delta, 0, sizeof(sps->mode_delta)); } set_filter_level_delta(bitbuf, sps); } vp8e_put_lit(bitbuf, sps->dct_partitions, 2); vp8e_put_lit(bitbuf, ctx->rc->qp_hdr, 7); vp8e_put_lit(bitbuf, 0, 1); vp8e_put_lit(bitbuf, 0, 1); vp8e_put_lit(bitbuf, 0, 1); vp8e_put_lit(bitbuf, 0, 1); vp8e_put_lit(bitbuf, 0, 1); if (!cur_pic->i_frame) { HalVp8eRefPic *ref_pic_list = ctx->picbuf.ref_pic_list; vp8e_put_lit(bitbuf, cur_pic->grf, 1); /* Grf refresh */ vp8e_put_lit(bitbuf, cur_pic->arf, 1); /* Arf refresh */ if (!cur_pic->grf) { if (ref_pic_list[0].grf) { vp8e_put_lit(bitbuf, 1, 2); /* Ipf -> grf */ } else if (ref_pic_list[2].grf) { vp8e_put_lit(bitbuf, 2, 2); /* Arf -> grf */ } else { vp8e_put_lit(bitbuf, 0, 2); /* Not updated */ } } if (!cur_pic->arf) { if (ref_pic_list[0].arf) { vp8e_put_lit(bitbuf, 1, 2); /* Ipf -> arf */ } else if (ref_pic_list[1].arf) { vp8e_put_lit(bitbuf, 2, 2); /* Grf -> arf */ } else { vp8e_put_lit(bitbuf, 0, 2); /* Not updated */ } } vp8e_put_lit(bitbuf, sps->sing_bias[1], 1); /* Grf */ vp8e_put_lit(bitbuf, sps->sing_bias[2], 1); /* Arf */ } vp8e_put_lit(bitbuf, sps->refresh_entropy, 1); if (!cur_pic->i_frame) { vp8e_put_lit(bitbuf, cur_pic->ipf, 1); } vp8e_calc_coeff_prob(bitbuf, &entropy->coeff_prob, &entropy->old_coeff_prob); vp8e_put_lit(bitbuf, 1, 1); vp8e_put_lit(bitbuf, entropy->skip_false_prob, 8); if (cur_pic->i_frame) return MPP_OK; vp8e_put_lit(bitbuf, entropy->intra_prob, 8); vp8e_put_lit(bitbuf, entropy->last_prob, 8); vp8e_put_lit(bitbuf, entropy->gf_prob, 8); vp8e_put_lit(bitbuf, 0, 1); vp8e_put_lit(bitbuf, 0, 1); vp8e_calc_mv_prob(bitbuf, &entropy->mv_prob, &entropy->old_mv_prob); return MPP_OK; } static MPP_RET set_new_frame(void *hal) { RK_S32 i; RK_S32 qp; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eSps *sps = &ctx->sps; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; hw_cfg->output_strm_size /= 8; hw_cfg->output_strm_size &= (~0x07); { hw_cfg->output_strm_offset += ctx->bitbuf[1].byte_cnt; hw_cfg->first_free_bit = (hw_cfg->output_strm_offset & 0x07) * 8; } if (hw_cfg->first_free_bit != 0) { RK_U32 val; RK_U8 *pTmp = (RK_U8 *)((size_t)(ctx->bitbuf[1].data) & (~0x07)); for (val = 6; val >= hw_cfg->first_free_bit / 8; val--) { pTmp[val] = 0; } val = pTmp[0] << 24; val |= pTmp[1] << 16; val |= pTmp[2] << 8; val |= pTmp[3]; hw_cfg->strm_start_msb = val; if (hw_cfg->first_free_bit > 32) { val = pTmp[4] << 24; val |= pTmp[5] << 16; val |= pTmp[6] << 8; hw_cfg->strm_start_lsb = val; } else { hw_cfg->strm_start_lsb = 0; } } else { hw_cfg->strm_start_msb = hw_cfg->strm_start_lsb = 0; } if (sps->quarter_pixel_mv == 0) { hw_cfg->disable_qp_mv = 1; } else if (sps->quarter_pixel_mv == 1) { if (ctx->mb_per_frame > 8160) hw_cfg->disable_qp_mv = 1; else hw_cfg->disable_qp_mv = 0; } else { hw_cfg->disable_qp_mv = 0; } hw_cfg->enable_cabac = 1; if (sps->split_mv == 0) hw_cfg->split_mv_mode = 0; else if (sps->split_mv == 1) { if (ctx->mb_per_frame > 1584) hw_cfg->split_mv_mode = 0; else hw_cfg->split_mv_mode = 1; } else hw_cfg->split_mv_mode = 1; qp = ctx->rc->qp_hdr; if (hw_cfg->inter_favor == -1) { RK_S32 tmp = 128 - ctx->entropy.intra_prob; if (tmp < 0) { hw_cfg->inter_favor = tmp & 0xFFFF; } else { tmp = qp * 2 - 40; hw_cfg->inter_favor = MPP_MAX(0, tmp); } } if (hw_cfg->diff_mv_penalty[0] == -1) hw_cfg->diff_mv_penalty[0] = 64 / 2; if (hw_cfg->diff_mv_penalty[1] == -1) hw_cfg->diff_mv_penalty[1] = 60 / 2 * 32; if (hw_cfg->diff_mv_penalty[2] == -1) hw_cfg->diff_mv_penalty[2] = 8; if (hw_cfg->skip_penalty == -1) hw_cfg->skip_penalty = (qp >= 100) ? (3 * qp / 4) : 0; /* Zero/nearest/near */ if (hw_cfg->golden_penalty == -1) hw_cfg->golden_penalty = MPP_MAX(0, 5 * qp / 4 - 10); if (hw_cfg->split_penalty[0] == 0) hw_cfg->split_penalty[0] = MPP_MIN(1023, vp8_split_penalty_tbl[qp] / 2); if (hw_cfg->split_penalty[1] == 0) hw_cfg->split_penalty[1] = MPP_MIN(1023, (2 * vp8_split_penalty_tbl[qp] + 40) / 4); if (hw_cfg->split_penalty[3] == 0) hw_cfg->split_penalty[3] = MPP_MIN(511, (8 * vp8_split_penalty_tbl[qp] + 500) / 16); for (i = 0; i < 128; i++) { RK_S32 y, x; hw_cfg->dmv_penalty[i] = i * 2; y = vp8e_calc_cost_mv(i * 2, ctx->entropy.mv_prob[0]); /* mv y */ x = vp8e_calc_cost_mv(i * 2, ctx->entropy.mv_prob[1]); /* mv x */ hw_cfg->dmv_qpel_penalty[i] = MPP_MIN(255, (y + x + 1) / 2 * weight_tbl[qp] >> 8); } for (i = 0; i < 4; i++) { qp = ctx->ppss.pps->qp_sgm[i]; hw_cfg->y1_quant_dc[i] = ctx->qp_y1[qp].quant[0]; hw_cfg->y1_quant_ac[i] = ctx->qp_y1[qp].quant[1]; hw_cfg->y2_quant_dc[i] = ctx->qp_y2[qp].quant[0]; hw_cfg->y2_quant_ac[i] = ctx->qp_y2[qp].quant[1]; hw_cfg->ch_quant_dc[i] = ctx->qp_ch[qp].quant[0]; hw_cfg->ch_quant_ac[i] = ctx->qp_ch[qp].quant[1]; hw_cfg->y1_zbin_dc[i] = ctx->qp_y1[qp].zbin[0]; hw_cfg->y1_zbin_ac[i] = ctx->qp_y1[qp].zbin[1]; hw_cfg->y2_zbin_dc[i] = ctx->qp_y2[qp].zbin[0]; hw_cfg->y2_zbin_ac[i] = ctx->qp_y2[qp].zbin[1]; hw_cfg->ch_zbin_dc[i] = ctx->qp_ch[qp].zbin[0]; hw_cfg->ch_zbin_ac[i] = ctx->qp_ch[qp].zbin[1]; hw_cfg->y1_round_dc[i] = ctx->qp_y1[qp].round[0]; hw_cfg->y1_round_ac[i] = ctx->qp_y1[qp].round[1]; hw_cfg->y2_round_dc[i] = ctx->qp_y2[qp].round[0]; hw_cfg->y2_round_ac[i] = ctx->qp_y2[qp].round[1]; hw_cfg->ch_round_dc[i] = ctx->qp_ch[qp].round[0]; hw_cfg->ch_round_ac[i] = ctx->qp_ch[qp].round[1]; hw_cfg->y1_dequant_dc[i] = ctx->qp_y1[qp].dequant[0]; hw_cfg->y1_dequant_ac[i] = ctx->qp_y1[qp].dequant[1]; hw_cfg->y2_dequant_dc[i] = ctx->qp_y2[qp].dequant[0]; hw_cfg->y2_dequant_ac[i] = ctx->qp_y2[qp].dequant[1]; hw_cfg->ch_dequant_dc[i] = ctx->qp_ch[qp].dequant[0]; hw_cfg->ch_dequant_ac[i] = ctx->qp_ch[qp].dequant[1]; hw_cfg->filter_level[i] = ctx->ppss.pps->level_sgm[i]; } hw_cfg->bool_enc_value = ctx->bitbuf[1].bottom; hw_cfg->bool_enc_value_bits = 24 - ctx->bitbuf[1].bits_left; hw_cfg->bool_enc_range = ctx->bitbuf[1].range; if (ctx->picbuf.cur_pic->i_frame) hw_cfg->frame_coding_type = 1; else hw_cfg->frame_coding_type = 0; hw_cfg->size_tbl_base = mpp_buffer_get_fd(buffers->hw_size_table_buf); hw_cfg->dct_partitions = sps->dct_partitions; hw_cfg->filter_disable = sps->filter_type; hw_cfg->filter_sharpness = sps->filter_sharpness; hw_cfg->segment_enable = ctx->ppss.pps->segment_enabled; hw_cfg->segment_map_update = ctx->ppss.pps->sgm.map_modified; ctx->ppss.pps->sgm.map_modified = 0; for (i = 0; i < 4; i++) { hw_cfg->lf_ref_delta[i] = sps->ref_delta[i]; hw_cfg->lf_mode_delta[i] = sps->mode_delta[i]; } set_intra_pred_penalties(hw_cfg, qp); memset(mpp_buffer_get_ptr(buffers->hw_prob_count_buf), 0, VP8_PROB_COUNT_BUF_SIZE); return MPP_OK; } static MPP_RET set_code_frame(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *) hal; vp8e_init_entropy(ctx); set_segmentation(ctx); set_filter(ctx); set_frame_header(ctx); set_new_frame(ctx); vp8e_write_entropy_tables(ctx); return MPP_OK; } static void reset_refpic(HalVp8eRefPic *refPic) { refPic->poc = -1; refPic->i_frame = 0; refPic->p_frame = 0; refPic->show = 0; refPic->ipf = 0; refPic->arf = 0; refPic->grf = 0; refPic->search = 0; } static void init_ref_pic_list(HalVp8ePicBuf *picbuf) { RK_S32 i, j; HalVp8eRefPic *ref_pic = picbuf->ref_pic; HalVp8eRefPic *cur_pic = picbuf->cur_pic; HalVp8eRefPic *ref_pic_list = picbuf->ref_pic_list; j = 0; for (i = 0; i < picbuf->size + 1; i++) { if (ref_pic[i].ipf && (&ref_pic[i] != cur_pic)) { ref_pic_list[j++] = ref_pic[i]; break; } } for (i = 0; i < picbuf->size + 1; i++) { if (ref_pic[i].grf && (&ref_pic[i] != cur_pic)) { ref_pic_list[j++] = ref_pic[i]; break; } } for (i = 0; i < picbuf->size + 1; i++) { if (ref_pic[i].arf && (&ref_pic[i] != cur_pic)) { ref_pic_list[j] = ref_pic[i]; break; } } for (i = 0; i < picbuf->size; i++) { ref_pic_list[i].ipf = 0; ref_pic_list[i].grf = 0; ref_pic_list[i].arf = 0; } } static MPP_RET init_picbuf(void *hal) { RK_S32 i = 0; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; HalVp8ePicBuf *buf = &ctx->picbuf; if (buf->cur_pic->i_frame) { buf->cur_pic->p_frame = 0; buf->cur_pic->ipf = 1; buf->cur_pic->grf = 1; buf->cur_pic->arf = 1; for (i = 0; i < 4; i++) { if (&buf->ref_pic[i] != buf->cur_pic) { reset_refpic(&buf->ref_pic[i]); } } } for (i = 0; i < 3; i++) { reset_refpic(&buf->ref_pic_list[i]); } init_ref_pic_list(buf); return MPP_OK; } static MPP_RET set_picbuf_ref(void *hal) { RK_S32 i = 0; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; HalVp8ePicBuf *pic_buf = &ctx->picbuf; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; HalVp8eRefPic *ref_pic_list = pic_buf->ref_pic_list; { RK_S32 no_grf = 0; RK_S32 no_arf = 0; if (pic_buf->size < 2) { no_grf = 1; pic_buf->cur_pic->grf = 0; } if (pic_buf->size < 3) { no_arf = 1; pic_buf->cur_pic->arf = 0; } for (i = 0; i < pic_buf->size; i++) { if (pic_buf->cur_pic->grf || no_grf) pic_buf->ref_pic_list[i].grf = 0; if (pic_buf->cur_pic->arf || no_arf) pic_buf->ref_pic_list[i].arf = 0; } } { RK_S32 ref_idx = -1; RK_S32 ref_idx2 = -1; for (i = 0; i < 3; i++) { if ((i < pic_buf->size) && ref_pic_list[i].search) { if (ref_idx == -1) ref_idx = i; else if (ref_idx2 == -1) ref_idx2 = i; else ref_pic_list[i].search = 0; } else { ref_pic_list[i].search = 0; } } if (ref_idx == -1) ref_idx = 0; hw_cfg->mv_ref_idx[0] = hw_cfg->mv_ref_idx[1] = ref_idx; if (pic_buf->cur_pic->p_frame) { pic_buf->ref_pic_list[ref_idx].search = 1; hw_cfg->internal_img_lum_base_r[0] = ref_pic_list[ref_idx].picture.lum; hw_cfg->internal_img_chr_base_r[0] = ref_pic_list[ref_idx].picture.cb; hw_cfg->internal_img_lum_base_r[1] = ref_pic_list[ref_idx].picture.lum; hw_cfg->internal_img_chr_base_r[1] = ref_pic_list[ref_idx].picture.cb; hw_cfg->mv_ref_idx[0] = hw_cfg->mv_ref_idx[1] = ref_idx; hw_cfg->ref2_enable = 0; if (ref_idx2 != -1) { hw_cfg->internal_img_lum_base_r[1] = ref_pic_list[ref_idx2].picture.lum; hw_cfg->internal_img_chr_base_r[1] = ref_pic_list[ref_idx2].picture.cb; hw_cfg->mv_ref_idx[1] = ref_idx2; hw_cfg->ref2_enable = 1; } } } hw_cfg->rec_write_disable = 0; if (!pic_buf->cur_pic->picture.lum) { HalVp8eRefPic *cur_pic = pic_buf->cur_pic; HalVp8eRefPic *cand; RK_S32 recIdx = -1; for (i = 0; i < pic_buf->size + 1; i++) { cand = &pic_buf->ref_pic[i]; if (cand == cur_pic) continue; if (((cur_pic->ipf | cand->ipf) == cur_pic->ipf) && ((cur_pic->grf | cand->grf) == cur_pic->grf) && ((cur_pic->arf | cand->arf) == cur_pic->arf)) recIdx = i; } if (recIdx >= 0) { cur_pic->picture.lum = pic_buf->ref_pic[recIdx].picture.lum; pic_buf->ref_pic[recIdx].picture.lum = 0; } else { hw_cfg->rec_write_disable = 1; } } hw_cfg->internal_img_lum_base_w = pic_buf->cur_pic->picture.lum; hw_cfg->internal_img_chr_base_w = pic_buf->cur_pic->picture.cb; return MPP_OK; } static void write_ivf_header(void *hal, RK_U8 *out) { RK_U8 data[IVF_HDR_BYTES] = {0}; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; MppEncPrepCfg *prep = &ctx->cfg->prep; MppEncRcCfg *rc = &ctx->cfg->rc; data[0] = 'D'; data[1] = 'K'; data[2] = 'I'; data[3] = 'F'; data[6] = 32; data[8] = 'V'; data[9] = 'P'; data[10] = '8'; data[11] = '0'; data[12] = prep->width & 0xff; data[13] = (prep->width >> 8) & 0xff; data[14] = prep->height & 0xff; data[15] = (prep->height >> 8) & 0xff; data[16] = rc->fps_out_num & 0xff; data[17] = (rc->fps_out_num >> 8) & 0xff; data[18] = (rc->fps_out_num >> 16) & 0xff; data[19] = (rc->fps_out_num >> 24) & 0xff; data[20] = rc->fps_out_denorm & 0xff; data[21] = (rc->fps_out_denorm >> 8) & 0xff; data[22] = (rc->fps_out_denorm >> 16) & 0xff; data[23] = (rc->fps_out_denorm >> 24) & 0xff; data[24] = ctx->frame_cnt & 0xff; data[25] = (ctx->frame_cnt >> 8) & 0xff; data[26] = (ctx->frame_cnt >> 16) & 0xff; data[27] = (ctx->frame_cnt >> 24) & 0xff; memcpy(out, data, IVF_HDR_BYTES); } static void write_ivf_frame(void *hal, RK_U8 *out) { RK_U8 data[IVF_FRM_BYTES]; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; RK_S32 byte_cnt = ctx->frame_size; data[0] = byte_cnt & 0xff; data[1] = (byte_cnt >> 8) & 0xff; data[2] = (byte_cnt >> 16) & 0xff; data[3] = (byte_cnt >> 24) & 0xff; data[4] = ctx->frame_cnt & 0xff; data[5] = (ctx->frame_cnt >> 8) & 0xff; data[6] = (ctx->frame_cnt >> 16) & 0xff; data[7] = (ctx->frame_cnt >> 24) & 0xff; data[8] = (ctx->frame_cnt >> 32) & 0xff; data[9] = (ctx->frame_cnt >> 40) & 0xff; data[10] = (ctx->frame_cnt >> 48) & 0xff; data[11] = (ctx->frame_cnt >> 56) & 0xff; memcpy(out, data, IVF_FRM_BYTES); } static MPP_RET set_frame_tag(void *hal) { RK_S32 tmp = 0; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; HalVp8ePicBuf *pic_buf = &ctx->picbuf; HalVp8eRefPic *cur_pic = pic_buf->cur_pic; Vp8ePutBitBuf *bitbuf = &ctx->bitbuf[0]; tmp = ((ctx->bitbuf[1].byte_cnt) << 5) | ((cur_pic->show ? 1 : 0) << 4) | (ctx->sps.profile << 1) | (cur_pic->i_frame ? 0 : 1); vp8e_put_byte(bitbuf, tmp & 0xff); vp8e_put_byte(bitbuf, (tmp >> 8) & 0xff); vp8e_put_byte(bitbuf, (tmp >> 16) & 0xff); if (!cur_pic->i_frame) return MPP_NOK; vp8e_put_byte(bitbuf, 0x9d); vp8e_put_byte(bitbuf, 0x01); vp8e_put_byte(bitbuf, 0x2a); tmp = ctx->sps.pic_width_in_pixel | (ctx->sps.horizontal_scaling << 14); vp8e_put_byte(bitbuf, tmp & 0xff); vp8e_put_byte(bitbuf, tmp >> 8); tmp = ctx->sps.pic_height_in_pixel | (ctx->sps.vertical_scaling << 14); vp8e_put_byte(bitbuf, tmp & 0xff); vp8e_put_byte(bitbuf, tmp >> 8); return MPP_OK; } static MPP_RET set_data_part_size(void *hal) { RK_S32 i = 0; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; if (!ctx->sps.dct_partitions) return MPP_NOK; for (i = 2; i < ctx->sps.partition_cnt - 1; i++) { Vp8ePutBitBuf *bitbuf = ctx->bitbuf; RK_S32 tmp = bitbuf[i].data - bitbuf[i].p_data; vp8e_put_byte(&bitbuf[1], tmp & 0xff); vp8e_put_byte(&bitbuf[1], (tmp >> 8) & 0xff); vp8e_put_byte(&bitbuf[1], (tmp >> 16) & 0xff); } return MPP_OK; } static MPP_RET update_picbuf(HalVp8ePicBuf *picbuf) { RK_S32 i , j; HalVp8eRefPic *ref_pic_list = picbuf->ref_pic_list; HalVp8eRefPic *ref_pic = picbuf->ref_pic; HalVp8eRefPic *cur_pic = picbuf->cur_pic; picbuf->last_pic = picbuf->cur_pic; for (i = 0; i < picbuf->size + 1; i++) { if (&ref_pic[i] == cur_pic) continue; if (cur_pic->ipf) ref_pic[i].ipf = 0; if (cur_pic->grf) ref_pic[i].grf = 0; if (cur_pic->arf) ref_pic[i].arf = 0; } for (i = 0; i < picbuf->size; i++) { for (j = 0; j < picbuf->size + 1; j++) { if (ref_pic_list[i].grf) ref_pic[j].grf = 0; if (ref_pic_list[i].arf) ref_pic[j].arf = 0; } } for (i = 0; i < picbuf->size; i++) { if (ref_pic_list[i].grf) ref_pic_list[i].refPic->grf = 1; if (ref_pic_list[i].arf) ref_pic_list[i].refPic->arf = 1; } for (i = 0; i < picbuf->size + 1; i++) { HalVp8eRefPic *tmp = &ref_pic[i]; if (!tmp->ipf && !tmp->arf && !tmp->grf) { picbuf->cur_pic = &ref_pic[i]; break; } } return MPP_OK; } static MPP_RET set_parameter(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eSps *sps = &ctx->sps; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; MppEncPrepCfg *set = &ctx->cfg->prep; RK_S32 width = 16 * ((set->width + 15) / 16); RK_S32 height = 16 * ((set->height + 15) / 16); RK_U32 stride = MPP_ALIGN(width, 16); //TODO handle rotation ctx->mb_per_frame = width / 16 * height / 16; ctx->mb_per_row = width / 16; ctx->mb_per_col = height / 16; sps->pic_width_in_pixel = width; sps->pic_height_in_pixel = height; sps->pic_width_in_mbs = width / 16; sps->pic_height_in_mbs = height / 16; sps->horizontal_scaling = 0; sps->vertical_scaling = 0; sps->color_type = 0; sps->clamp_type = 0; sps->dct_partitions = 0; sps->partition_cnt = 2 + (1 << sps->dct_partitions); sps->profile = 1; sps->filter_type = 0; sps->filter_level = 0; sps->filter_sharpness = 0; sps->auto_filter_level = 1; sps->auto_filter_sharpness = 1; sps->quarter_pixel_mv = 1; sps->split_mv = 1; sps->refresh_entropy = 1; memset(sps->sing_bias, 0, sizeof(sps->sing_bias)); sps->filter_delta_enable = 1; memset(sps->ref_delta, 0, sizeof(sps->ref_delta)); memset(sps->mode_delta, 0, sizeof(sps->mode_delta)); hw_cfg->input_rotation = set->rotation; { RK_U32 tmp = 0; RK_U32 hor_offset_src = 0; RK_U32 ver_offset_src = 0; RK_U8 video_stab = 0; if (set->format == MPP_FMT_YUV420SP || set->format == MPP_FMT_YUV420P) { tmp = ver_offset_src; tmp *= stride; tmp += hor_offset_src; hw_cfg->input_lum_base += (tmp & (~7)); hw_cfg->input_luma_base_offset = tmp & 7; if (video_stab) hw_cfg->vs_next_luma_base += (tmp & (~7)); if (set->format == MPP_FMT_YUV420P) { tmp = ver_offset_src / 2; tmp *= stride / 2; tmp += hor_offset_src / 2; hw_cfg->input_cb_base += (tmp & (~7)); hw_cfg->input_cr_base += (tmp & (~7)); hw_cfg->input_chroma_base_offset = tmp & 7; } else { tmp = ver_offset_src / 2; tmp *= stride / 2; tmp += hor_offset_src / 2; tmp *= 2; hw_cfg->input_cb_base += (tmp & (~7)); hw_cfg->input_chroma_base_offset = tmp & 7; } } else if (set->format <= MPP_FMT_BGR444 && set->format >= MPP_FMT_RGB565) { tmp = ver_offset_src; tmp *= stride; tmp += hor_offset_src; tmp *= 2; hw_cfg->input_lum_base += (tmp & (~7)); hw_cfg->input_luma_base_offset = tmp & 7; hw_cfg->input_chroma_base_offset = (hw_cfg->input_luma_base_offset / 4) * 4; if (video_stab) hw_cfg->vs_next_luma_base += (tmp & (~7)); } else { tmp = ver_offset_src; tmp *= stride; tmp += hor_offset_src; tmp *= 4; hw_cfg->input_lum_base += (tmp & (~7)); hw_cfg->input_luma_base_offset = (tmp & 7) / 2; if (video_stab) hw_cfg->vs_next_luma_base += (tmp & (~7)); } hw_cfg->mbs_in_row = (set->width + 15) / 16; hw_cfg->mbs_in_col = (set->height + 15) / 16; hw_cfg->pixels_on_row = stride; } if (set->width & 0x0F) hw_cfg->x_fill = (16 - (set->width & 0x0F)) / 4; else hw_cfg->x_fill = 0; if (set->height & 0x0F) hw_cfg->y_fill = 16 - (set->height & 0x0F); else hw_cfg->y_fill = 0; hw_cfg->vs_mode = 0; switch (set->color) { case MPP_FRAME_SPC_RGB: /* BT.601 */ default: /* Y = 0.2989 R + 0.5866 G + 0.1145 B * Cb = 0.5647 (B - Y) + 128 * Cr = 0.7132 (R - Y) + 128 */ hw_cfg->rgb_coeff_a = 19589; hw_cfg->rgb_coeff_b = 38443; hw_cfg->rgb_coeff_c = 7504; hw_cfg->rgb_coeff_e = 37008; hw_cfg->rgb_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 */ hw_cfg->rgb_coeff_a = 13933; hw_cfg->rgb_coeff_b = 46871; hw_cfg->rgb_coeff_c = 732; hw_cfg->rgb_coeff_e = 35317; hw_cfg->rgb_coeff_f = 41615; break; } hw_cfg->r_mask_msb = hw_cfg->g_mask_msb = hw_cfg->b_mask_msb = 0; VepuFormatCfg fmt_cfg; if (!get_vepu_fmt(&fmt_cfg, set->format)) { hw_cfg->input_format = fmt_cfg.format; hw_cfg->r_mask_msb = fmt_cfg.r_mask; hw_cfg->g_mask_msb = fmt_cfg.g_mask; hw_cfg->b_mask_msb = fmt_cfg.b_mask; } else return MPP_NOK; return MPP_OK; } static MPP_RET set_picbuf(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; // find one dpb for current picture { RK_U32 i = 0; RK_S32 width = ctx->sps.pic_width_in_mbs * 16; RK_S32 height = ctx->sps.pic_height_in_mbs * 16; HalVp8ePicBuf *picbuf = &ctx->picbuf; memset(picbuf->ref_pic, 0, sizeof(picbuf->ref_pic)); memset(picbuf->ref_pic_list, 0, sizeof(picbuf->ref_pic_list)); for (i = 0; i < REF_FRAME_COUNT + 1; i++) { picbuf->ref_pic[i].picture.lum_width = width; picbuf->ref_pic[i].picture.lum_height = height; picbuf->ref_pic[i].picture.ch_width = width / 2; picbuf->ref_pic[i].picture.ch_height = height / 2; picbuf->ref_pic[i].picture.lum = 0; picbuf->ref_pic[i].picture.cb = 0; } picbuf->cur_pic = &picbuf->ref_pic[0]; } ctx->ppss.size = 1; ctx->ppss.store = (Pps *)mpp_calloc(Pps, 1); if (ctx->ppss.store == NULL) { mpp_err("failed to malloc ppss store.\n"); goto __ERR_RET; } ctx->ppss.pps = ctx->ppss.store; ctx->ppss.pps->segment_enabled = 0; ctx->ppss.pps->sgm.map_modified = 0; return MPP_OK; __ERR_RET: return MPP_NOK; } static MPP_RET alloc_buffer(void *hal) { MPP_RET ret = MPP_OK; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; MppEncPrepCfg *pre = &ctx->cfg->prep; RK_U32 mb_total = ctx->mb_per_frame; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; //set coding format as VP8 hw_cfg->coding_type = 1; ret = mpp_buffer_group_get_internal(&buffers->hw_buf_grp, MPP_BUFFER_TYPE_ION); if (ret) { mpp_err("buf group get failed ret %d\n", ret); goto __ERR_RET; } //add 128 bytes to avoid kernel crash ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_luma_buf, MPP_ALIGN(mb_total * (16 * 16), SZ_4K) + SZ_4K); if (ret) { mpp_err("hw_luma_buf get failed ret %d\n", ret); goto __ERR_RET; } { RK_U32 i = 0; for (i = 0; i < 2; i++) { //add 128 bytes to avoid kernel crash ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_cbcr_buf[i], MPP_ALIGN(mb_total * (2 * 8 * 8), SZ_4K) + SZ_4K); if (ret) { mpp_err("hw_cbcr_buf[%d] get failed ret %d\n", i, ret); goto __ERR_RET; } } } hw_cfg->internal_img_lum_base_w = mpp_buffer_get_fd(buffers->hw_luma_buf); hw_cfg->internal_img_chr_base_w = mpp_buffer_get_fd(buffers->hw_cbcr_buf[0]); hw_cfg->internal_img_lum_base_r[0] = mpp_buffer_get_fd(buffers->hw_luma_buf); hw_cfg->internal_img_chr_base_r[0] = mpp_buffer_get_fd(buffers->hw_cbcr_buf[1]); { /* NAL size table, table size must be 64-bit multiple, * space for SEI, MVC prefix, filler and zero at the end of table. * At least 1 macroblock row in every slice. * Also used for VP8 partitions. */ RK_U32 size_tbl = MPP_ALIGN(sizeof(RK_U32) * (pre->height + 4), 8); ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_size_table_buf, size_tbl); if (ret) { mpp_err("hw_size_table_buf get failed ret %d\n", ret); goto __ERR_RET; } } { RK_U32 cabac_tbl_size = 8 * 55 + 8 * 96; ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_cabac_table_buf, cabac_tbl_size); if (ret) { mpp_err("hw_cabac_table_buf get failed\n"); goto __ERR_RET; } } hw_cfg->cabac_tbl_base = mpp_buffer_get_fd(buffers->hw_cabac_table_buf); ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_mv_output_buf, mb_total * 4); if (ret) { mpp_err("hw_mv_output_buf get failed ret %d\n", ret); goto __ERR_RET; } hw_cfg->mv_output_base = mpp_buffer_get_fd(buffers->hw_mv_output_buf); memset(mpp_buffer_get_ptr(buffers->hw_mv_output_buf), 0, sizeof(RK_U32) * mb_total); ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_prob_count_buf, VP8_PROB_COUNT_BUF_SIZE); if (ret) { mpp_err("hw_prob_count_buf get failed ret %d\n", ret); goto __ERR_RET; } hw_cfg->prob_count_base = mpp_buffer_get_fd(buffers->hw_prob_count_buf); { /* VP8: Segmentation map, 4 bits/mb, 64-bit multiple. */ RK_U32 segment_map_size = (mb_total * 4 + 63) / 64 * 8; ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_segment_map_buf, segment_map_size); if (ret) { mpp_err("hw_segment_map_buf get failed ret %d\n", ret); goto __ERR_RET; } hw_cfg->segment_map_base = mpp_buffer_get_fd(buffers->hw_segment_map_buf); memset(mpp_buffer_get_ptr(buffers->hw_segment_map_buf), 0, segment_map_size / 4); } { RK_U32 i = 0; ctx->picbuf.size = 1; for (i = 0; i < 1; i++) ctx->picbuf.ref_pic[i].picture.lum = mpp_buffer_get_fd(buffers->hw_luma_buf); for (i = 0; i < 2; i++) ctx->picbuf.ref_pic[i].picture.cb = mpp_buffer_get_fd(buffers->hw_cbcr_buf[i]); } { RK_U32 pic_size = MPP_ALIGN(pre->width, 16) * MPP_ALIGN(pre->height, 16) * 3 / 2; RK_U32 out_size = pic_size / 2; ret = mpp_buffer_get(buffers->hw_buf_grp, &buffers->hw_out_buf, out_size); if (ret) { mpp_err("hw_out_buf get failed ret %d\n", ret); goto __ERR_RET; } } ctx->regs = mpp_calloc(RK_U32, ctx->reg_size); if (!ctx->regs) { mpp_err("failed to calloc regs.\n"); goto __ERR_RET; } hw_cfg->intra_16_favor = -1; hw_cfg->prev_mode_favor = -1; hw_cfg->inter_favor = -1; hw_cfg->skip_penalty = -1; hw_cfg->diff_mv_penalty[0] = -1; hw_cfg->diff_mv_penalty[1] = -1; hw_cfg->diff_mv_penalty[2] = -1; hw_cfg->split_penalty[0] = 0; hw_cfg->split_penalty[1] = 0; hw_cfg->split_penalty[2] = 0x3FF; hw_cfg->split_penalty[3] = 0; hw_cfg->zero_mv_favor = 0; hw_cfg->intra_area_top = hw_cfg->intra_area_bottom = 255; hw_cfg->intra_area_left = hw_cfg->intra_area_right = 255; hw_cfg->roi1_top = hw_cfg->roi1_bottom = 255; hw_cfg->roi1_left = hw_cfg->roi1_right = 255; hw_cfg->roi2_top = hw_cfg->roi2_bottom = 255; hw_cfg->roi2_left = hw_cfg->roi2_right = 255; return ret; __ERR_RET: if (buffers) hal_vp8e_buf_free(hal); return ret; } MPP_RET hal_vp8e_enc_strm_code(void *hal, HalEncTask *task) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eHwCfg *hw_cfg = &ctx->hw_cfg; MppEncCfgSet *cfg = ctx->cfg; MppEncPrepCfg *prep = &cfg->prep; { RK_U32 i = 0; for (i = 0; i < 9; i++) { ctx->p_out_buf[i] = NULL; ctx->stream_size[i] = 0; } } { HalEncTask *enc_task = task; RK_U32 hor_stride = MPP_ALIGN(prep->width, 16); RK_U32 ver_stride = MPP_ALIGN(prep->height, 16); RK_U32 offset_uv = hor_stride * ver_stride; hw_cfg->input_lum_base = mpp_buffer_get_fd(enc_task->input); hw_cfg->input_cb_base = hw_cfg->input_lum_base; hw_cfg->input_cb_offset = offset_uv; hw_cfg->input_cr_base = hw_cfg->input_cb_base; hw_cfg->input_cr_offset = offset_uv * 5 / 4; } // split memory for vp8 partition { RK_S32 offset = 0; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; RK_U8 *p_end = NULL; RK_U32 buf_size = mpp_buffer_get_size(buffers->hw_out_buf); RK_U32 bus_addr = mpp_buffer_get_fd(buffers->hw_out_buf); RK_U8 *p_start = mpp_buffer_get_ptr(buffers->hw_out_buf); p_end = p_start + 3; if (ctx->frame_type == VP8E_FRM_KEY) p_end += 7;// frame tag len:I frame 10 byte, P frmae 3 byte. vp8e_set_buffer(&ctx->bitbuf[0], p_start, p_end - p_start); offset = p_end - p_start; hw_cfg->output_strm_base = bus_addr; hw_cfg->output_strm_offset = offset; p_start = p_end; p_end = p_start + buf_size / 10; p_end = (RK_U8 *)((size_t)p_end & ~0x7); vp8e_set_buffer(&ctx->bitbuf[1], p_start, p_end - p_start); offset += p_end - p_start; hw_cfg->partition_Base[0] = bus_addr; hw_cfg->partition_offset[0] = offset; p_start = p_end; p_end = mpp_buffer_get_ptr(buffers->hw_out_buf) + buf_size; p_end = (RK_U8 *)((size_t)p_end & ~0x7); vp8e_set_buffer(&ctx->bitbuf[2], p_start, p_end - p_start); offset += p_end - p_start; hw_cfg->partition_Base[1] = bus_addr; hw_cfg->partition_offset[1] = offset; hw_cfg->output_strm_size = p_end - p_start; p_start = p_end; } { HalVp8ePicBuf *pic_buf = &ctx->picbuf; pic_buf->cur_pic->show = 1; pic_buf->cur_pic->poc = ctx->frame_cnt; pic_buf->cur_pic->i_frame = (ctx->frame_type == VP8E_FRM_KEY); init_picbuf(ctx); if (ctx->frame_type == VP8E_FRM_P) { pic_buf->cur_pic->p_frame = 1; pic_buf->cur_pic->arf = 1; pic_buf->cur_pic->grf = 1; pic_buf->cur_pic->ipf = 1; pic_buf->ref_pic_list[0].search = 1; pic_buf->ref_pic_list[1].search = 1; pic_buf->ref_pic_list[2].search = 1; } if (ctx->rc->frame_coded == 0) return MPP_OK; if (ctx->rc->golden_picture_rate) { pic_buf->cur_pic->grf = 1; if (!pic_buf->cur_pic->arf) pic_buf->ref_pic_list[1].arf = 1; } } set_frame_params(ctx); set_picbuf_ref(ctx); set_code_frame(ctx); return MPP_OK; } MPP_RET hal_vp8e_init_qp_table(void *hal) { RK_S32 i = 0, j = 0; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; for (i = 0; i < QINDEX_RANGE; i++) { RK_S32 tmp = 0; Vp8eQp * qp = &ctx->qp_y1[i]; for (j = 0; j < 2; j++) { if (j == 0) { tmp = dc_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; } else { tmp = ac_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; } qp->quant[j] = MPP_MIN((1 << 16) / tmp, 0x3FFF); qp->zbin[j] = ((q_zbin_factors_tbl[i] * tmp) + 64) >> 7; qp->round[j] = (q_rounding_factors_tbl[i] * tmp) >> 7; qp->dequant[j] = tmp; } qp = &ctx->qp_y2[i]; for (j = 0; j < 2; j++) { if (j == 0) { tmp = dc_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; tmp = tmp * 2; } else { tmp = ac_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; tmp = (tmp * 155) / 100; if (tmp < 8) tmp = 8; } qp->quant[j] = MPP_MIN((1 << 16) / tmp, 0x3FFF); qp->zbin[j] = ((q_zbin_factors_tbl[i] * tmp) + 64) >> 7; qp->round[j] = (q_rounding_factors_tbl[i] * tmp) >> 7; qp->dequant[j] = tmp; } qp = &ctx->qp_ch[i]; for (j = 0; j < 2; j++) { if (j == 0) { tmp = dc_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; if (tmp > 132) tmp = 132; } else { tmp = ac_q_lookup_tbl[MPP_CLIP3(0, QINDEX_RANGE - 1, i)]; } qp->quant[j] = MPP_MIN((1 << 16) / tmp, 0x3FFF); qp->zbin[j] = ((q_zbin_factors_tbl[i] * tmp) + 64) >> 7; qp->round[j] = (q_rounding_factors_tbl[i] * tmp) >> 7; qp->dequant[j] = tmp; } } return MPP_OK; } MPP_RET hal_vp8e_update_buffers(void *hal, HalEncTask *task) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; const RK_U32 hw_offset = ctx->hw_cfg.first_free_bit / 8; RK_U32 *part = (RK_U32 *)mpp_buffer_get_ptr(buffers->hw_size_table_buf); ctx->bitbuf[1].byte_cnt += part[0] - hw_offset; ctx->bitbuf[1].data += part[0] - hw_offset; ctx->bitbuf[2].byte_cnt = part[1]; ctx->bitbuf[2].data += part[1]; ctx->bitbuf[3].byte_cnt = part[2]; ctx->bitbuf[3].data += part[2]; set_frame_tag(ctx); if (vp8e_buffer_gap(&ctx->bitbuf[1], 4) == MPP_OK) { set_data_part_size(ctx); } ctx->prev_frame_lost = 0; ctx->p_out_buf[0] = (RK_U32 *)ctx->bitbuf[0].p_data; ctx->p_out_buf[1] = (RK_U32 *)ctx->bitbuf[2].p_data; if (ctx->sps.dct_partitions) ctx->p_out_buf[2] = (RK_U32 *)ctx->bitbuf[3].p_data; ctx->stream_size[0] = ctx->bitbuf[0].byte_cnt + ctx->bitbuf[1].byte_cnt; ctx->stream_size[1] = ctx->bitbuf[2].byte_cnt; if (ctx->sps.dct_partitions) ctx->stream_size[2] = ctx->bitbuf[3].byte_cnt; ctx->frame_size = ctx->stream_size[0] + ctx->stream_size[1] + ctx->stream_size[2]; update_picbuf(&ctx->picbuf); { HalEncTask *enc_task = task; RK_U8 *p_out = mpp_buffer_get_ptr(enc_task->output); RK_S32 disable_ivf = ctx->cfg->codec.vp8.disable_ivf; if (!disable_ivf) { if (ctx->frame_cnt == 0) { write_ivf_header(hal, p_out); p_out += IVF_HDR_BYTES; enc_task->length += IVF_HDR_BYTES; } if (ctx->frame_size) { write_ivf_frame(ctx, p_out); p_out += IVF_FRM_BYTES; enc_task->length += IVF_FRM_BYTES; } } memcpy(p_out, ctx->p_out_buf[0], ctx->stream_size[0]); p_out += ctx->stream_size[0]; enc_task->length += ctx->stream_size[0]; memcpy(p_out, ctx->p_out_buf[1], ctx->stream_size[1]); p_out += ctx->stream_size[1]; enc_task->length += ctx->stream_size[1]; memcpy(p_out, ctx->p_out_buf[2], ctx->stream_size[2]); p_out += ctx->stream_size[2]; enc_task->length += ctx->stream_size[2]; } return MPP_OK; } MPP_RET hal_vp8e_setup(void *hal) { MPP_RET ret = MPP_OK; HalVp8eCtx *ctx = (HalVp8eCtx *)hal; if (set_parameter(ctx)) { mpp_err("set vp8e parameter failed"); return MPP_NOK; } if (set_picbuf(ctx)) { mpp_err("set vp8e picbuf failed, no enough memory"); return MPP_ERR_NOMEM; } ret = alloc_buffer(ctx); return ret; } MPP_RET hal_vp8e_buf_free(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; if (buffers->hw_luma_buf) { mpp_buffer_put(buffers->hw_luma_buf); buffers->hw_luma_buf = NULL; } { RK_U32 i = 0; for (i = 0; i < 2; i++) { if (buffers->hw_cbcr_buf[i]) { mpp_buffer_put(buffers->hw_cbcr_buf[i]); buffers->hw_cbcr_buf[i] = NULL; } } } if (buffers->hw_size_table_buf) { mpp_buffer_put(buffers->hw_size_table_buf); buffers->hw_size_table_buf = NULL; } if (buffers->hw_cabac_table_buf) { mpp_buffer_put(buffers->hw_cabac_table_buf); buffers->hw_cabac_table_buf = NULL; } if (buffers->hw_mv_output_buf) { mpp_buffer_put(buffers->hw_mv_output_buf); buffers->hw_mv_output_buf = NULL; } if (buffers->hw_prob_count_buf) { mpp_buffer_put(buffers->hw_prob_count_buf); buffers->hw_prob_count_buf = NULL; } if (buffers->hw_segment_map_buf) { mpp_buffer_put(buffers->hw_segment_map_buf); buffers->hw_segment_map_buf = NULL; } if (buffers->hw_out_buf) { mpp_buffer_put(buffers->hw_out_buf); buffers->hw_out_buf = NULL; } if (buffers->hw_buf_grp) { mpp_buffer_group_put(buffers->hw_buf_grp); buffers->hw_buf_grp = NULL; } return MPP_OK; }