/* * 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_entropy" #include #include "mpp_common.h" #include "hal_vp8e_base.h" #include "hal_vp8e_entropy.h" #include "hal_vp8e_putbit.h" #include "hal_vp8e_table.h" #define COST_BOOL(prob, bin)\ ((bin) ? vp8_prob_cost_tbl[255 - (prob)] : vp8_prob_cost_tbl[prob]) static RK_U32 calc_mvprob(RK_U32 left, RK_U32 right, RK_U32 prob) { RK_U32 p; if (left + right) { p = (left * 255) / (left + right); p &= -2; if (!p) p = 1; } else p = prob; return p; } static RK_U32 update_prob(RK_U32 prob, RK_U32 left, RK_U32 right, RK_U32 old_prob, RK_U32 new_prob, RK_U32 fixed) { RK_S32 u, s; u = (RK_S32)fixed + ((vp8_prob_cost_tbl[255 - prob] - vp8_prob_cost_tbl[prob]) >> 8); s = ((RK_S32)left * (vp8_prob_cost_tbl[old_prob] - vp8_prob_cost_tbl[new_prob]) + (RK_S32)right * (vp8_prob_cost_tbl[255 - old_prob] - vp8_prob_cost_tbl[255 - new_prob])) >> 8; return (s > u); } static RK_S32 get_cost_tree(Vp8eTree const *tree, RK_S32 *prob) { RK_S32 bit_cost = 0; RK_S32 value = tree->value; RK_S32 number = tree->number; RK_S32 const *index = tree->index; while (number--) { bit_cost += COST_BOOL(prob[*index++], (value >> number) & 1); } return bit_cost; } MPP_RET vp8e_init_entropy(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; Vp8eHalEntropy *entropy = &ctx->entropy; entropy->update_coeff_prob_flag = 0; if (!ctx->sps.refresh_entropy || ctx->picbuf.cur_pic->i_frame) { if (!entropy->default_coeff_prob_flag) { memcpy(entropy->coeff_prob, default_prob_coeff_tbl, sizeof(default_prob_coeff_tbl)); entropy->update_coeff_prob_flag = 1; } memcpy(entropy->mv_prob, default_prob_mv_tbl, sizeof(default_prob_mv_tbl)); entropy->default_coeff_prob_flag = 1; } memcpy(entropy->old_coeff_prob, entropy->coeff_prob, sizeof(entropy->coeff_prob)); if (ctx->frame_cnt == 0 || !ctx->last_frm_intra) memcpy(entropy->old_mv_prob, entropy->mv_prob, sizeof(entropy->mv_prob)); entropy->skip_false_prob = default_skip_false_prob_tbl[ctx->rc->qp_hdr]; if (ctx->frame_cnt == 0) return MPP_OK; if ((!ctx->picbuf.cur_pic->ipf) && (!ctx->picbuf.cur_pic->grf) && (!ctx->picbuf.cur_pic->arf)) return MPP_OK; if (ctx->prev_frame_lost) return MPP_OK; { RK_S32 i, j, k, l; RK_U32 p, left, right; RK_U32 old_p, upd_p = 0; RK_U32 type; RK_U32 branch_cnt[2]; RK_U16 *p_tmp = NULL; RK_U16 *p_cnt = (RK_U16 *)mpp_buffer_get_ptr(buffers->hw_prob_count_buf); for (i = 0; i < 4; i++) { for (j = 0; j < 7; j++) { for (k = 0; k < 3; k++) { RK_S32 tmp, ii; tmp = i * 7 * 3 + j * 3 + k; tmp += 2 * 4 * 7 * 3; ii = offset_tbl[tmp]; right = ii >= 0 ? p_cnt[ii] : 0; for (l = 2; l--;) { old_p = entropy->coeff_prob[i][j][k][l]; old_p = coeff_update_prob_tbl[i][j][k][l]; tmp -= 4 * 7 * 3; ii = offset_tbl[tmp]; left = ii >= 0 ? p_cnt[ii] : 0; if (left + right) { p = ((left * 256) + ((left + right) >> 1)) / (left + right); if (p > 255) p = 255; } else p = old_p; if (update_prob(upd_p, left, right, old_p, p, 8)) { entropy->coeff_prob[i][j][k][l] = p; entropy->update_coeff_prob_flag = 1; } right += left; } } } } if (entropy->update_coeff_prob_flag) entropy->default_coeff_prob_flag = 0; p_tmp = p_cnt + VP8_PROB_COUNT_MV_OFFSET; for (i = 0; i < 2; i++) { left = *p_tmp++; right = *p_tmp++; p = calc_mvprob(left, right, entropy->old_mv_prob[i][0]); if (update_prob(mv_update_prob_tbl[i][0], left, right, entropy->old_mv_prob[i][0], p, 6)) entropy->mv_prob[i][0] = p; right += left; left = *p_tmp++; right -= left - p_tmp[0]; p = calc_mvprob(left, right, entropy->old_mv_prob[i][1]); if (update_prob(mv_update_prob_tbl[i][1], left, right, entropy->old_mv_prob[i][1], p, 6)) entropy->mv_prob[i][1] = p; for (j = 0; j < 2; j++) { left = *p_tmp++; right = *p_tmp++; p = calc_mvprob(left, right, entropy->old_mv_prob[i][4 + j]); if (update_prob(mv_update_prob_tbl[i][4 + j], left, right, entropy->old_mv_prob[i][4 + j], p, 6)) entropy->mv_prob[i][4 + j] = p; branch_cnt[j] = left + right; } p = calc_mvprob(branch_cnt[0], branch_cnt[1], entropy->old_mv_prob[i][3]); if (update_prob(mv_update_prob_tbl[i][3], branch_cnt[0], branch_cnt[1], entropy->old_mv_prob[i][3], p, 6)) entropy->mv_prob[i][3] = p; type = branch_cnt[0] + branch_cnt[1]; for (j = 0; j < 2; j++) { left = *p_tmp++; right = *p_tmp++; p = calc_mvprob(left, right, entropy->old_mv_prob[i][7 + j]); if (update_prob(mv_update_prob_tbl[i][7 + j], left, right, entropy->old_mv_prob[i][7 + j], p, 6)) entropy->mv_prob[i][7 + j] = p; branch_cnt[j] = left + right; } p = calc_mvprob(branch_cnt[0], branch_cnt[1], entropy->old_mv_prob[i][6]); if (update_prob(mv_update_prob_tbl[i][6], branch_cnt[0], branch_cnt[1], entropy->old_mv_prob[i][6], p, 6)) entropy->mv_prob[i][6] = p; p = calc_mvprob(type, branch_cnt[0] + branch_cnt[1], entropy->old_mv_prob[i][2]); if (update_prob(mv_update_prob_tbl[i][2], type, branch_cnt[0] + branch_cnt[1], entropy->old_mv_prob[i][2], p, 6)) entropy->mv_prob[i][2] = p; } } { entropy->last_prob = 255; entropy->gf_prob = 128; memcpy(entropy->y_mode_prob, y_mode_prob_tbl, sizeof(y_mode_prob_tbl)); memcpy(entropy->uv_mode_prob, uv_mode_prob_tbl, sizeof(uv_mode_prob_tbl)); } return MPP_OK; } MPP_RET vp8e_swap_endian(RK_U32 *buf, RK_U32 bytes) { RK_U32 i = 0; RK_S32 words = bytes / 4; while (words > 0) { RK_U32 val = buf[i]; RK_U32 tmp = 0; tmp |= (val & 0xFF) << 24; tmp |= (val & 0xFF00) << 8; tmp |= (val & 0xFF0000) >> 8; tmp |= (val & 0xFF000000) >> 24; { RK_U32 val2 = buf[i + 1]; RK_U32 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++; } return MPP_OK; } MPP_RET vp8e_write_entropy_tables(void *hal) { HalVp8eCtx *ctx = (HalVp8eCtx *)hal; Vp8eVpuBuf *buffers = (Vp8eVpuBuf *)ctx->buffers; Vp8eHalEntropy *entropy = &ctx->entropy; RK_U8 *table = (RK_U8 *)mpp_buffer_get_ptr(buffers->hw_cabac_table_buf); /* Write probability tables to ASIC linear memory, reg + mem */ memset(table, 0, 56); // use 56 bytes table[0] = entropy->skip_false_prob; table[1] = entropy->intra_prob; table[2] = entropy->last_prob; table[3] = entropy->gf_prob; table[4] = entropy->segment_prob[0]; table[5] = entropy->segment_prob[1]; table[6] = entropy->segment_prob[2]; table[8] = entropy->y_mode_prob[0]; table[9] = entropy->y_mode_prob[1]; table[10] = entropy->y_mode_prob[2]; table[11] = entropy->y_mode_prob[3]; table[12] = entropy->uv_mode_prob[0]; table[13] = entropy->uv_mode_prob[1]; table[14] = entropy->uv_mode_prob[2]; /* MV probabilities x+y: short, sign, size 8-9 */ table[16] = entropy->mv_prob[1][0]; table[17] = entropy->mv_prob[0][0]; table[18] = entropy->mv_prob[1][1]; table[19] = entropy->mv_prob[0][1]; table[20] = entropy->mv_prob[1][17]; table[21] = entropy->mv_prob[1][18]; table[22] = entropy->mv_prob[0][17]; table[23] = entropy->mv_prob[0][18]; { RK_S32 i, j, k, l; /* MV X size */ for (i = 0; i < 8; i++) table[24 + i] = entropy->mv_prob[1][9 + i]; /* MV Y size */ for (i = 0; i < 8; i++) table[32 + i] = entropy->mv_prob[0][9 + i]; /* MV X short tree */ for (i = 0; i < 7; i++) table[40 + i] = entropy->mv_prob[1][2 + i]; /* MV Y short tree */ for (i = 0; i < 7; i++) table[48 + i] = entropy->mv_prob[0][2 + i]; /* Update the ASIC table when needed. */ if (entropy->update_coeff_prob_flag) { table += 56; /* DCT coeff probabilities 0-2, two fields per line. */ for (i = 0; i < 4; i++) for (j = 0; j < 8; j++) for (k = 0; k < 3; k++) { for (l = 0; l < 3; l++) { *table++ = entropy->coeff_prob[i][j][k][l]; } *table++ = 0; } /* ASIC second probability table in ext mem. * DCT coeff probabilities 4 5 6 7 8 9 10 3 on each line. * coeff 3 was moved from first table to second so it is last. */ for (i = 0; i < 4; i++) for (j = 0; j < 8; j++) for (k = 0; k < 3; k++) { for (l = 4; l < 11; l++) { *table++ = entropy->coeff_prob[i][j][k][l]; } *table++ = entropy->coeff_prob[i][j][k][3]; } } } table = mpp_buffer_get_ptr(buffers->hw_cabac_table_buf); if (entropy->update_coeff_prob_flag) vp8e_swap_endian((RK_U32 *) table, 56 + 8 * 48 + 8 * 96); else vp8e_swap_endian((RK_U32 *) table, 56); return MPP_OK; } RK_S32 vp8e_calc_cost_mv(RK_S32 mvd, RK_S32 *mv_prob) { RK_S32 i = 0; RK_S32 bit_cost = 0; RK_S32 tmp = MPP_ABS(mvd >> 1); if (tmp < 8) { bit_cost += COST_BOOL(mv_prob[0], 0); bit_cost += get_cost_tree(&mv_tree_tbl[tmp], mv_prob + 2); if (!tmp) return bit_cost; /* Sign */ bit_cost += COST_BOOL(mv_prob[1], mvd < 0); return bit_cost; } bit_cost += COST_BOOL(mv_prob[0], 1); for (i = 0; i < 3; i++) { bit_cost += COST_BOOL(mv_prob[9 + i], (tmp >> i) & 1); } for (i = 9; i > 3; i--) { bit_cost += COST_BOOL(mv_prob[9 + i], (tmp >> i) & 1); } if (tmp > 15) { bit_cost += COST_BOOL(mv_prob[9 + 3], (tmp >> 3) & 1); } bit_cost += COST_BOOL(mv_prob[1], mvd < 0); return bit_cost; } MPP_RET vp8e_calc_coeff_prob(Vp8ePutBitBuf *bitbuf, RK_S32 (*curr)[4][8][3][11], RK_S32 (*prev)[4][8][3][11]) { RK_S32 i, j, k, l; RK_S32 prob, new, old; for (i = 0; i < 4; i++) { for (j = 0; j < 8; j++) { for (k = 0; k < 3; k++) { for (l = 0; l < 11; l++) { prob = coeff_update_prob_tbl[i][j][k][l]; old = (RK_S32) (*prev)[i][j][k][l]; new = (RK_S32) (*curr)[i][j][k][l]; if (new == old) { vp8e_put_bool(bitbuf, prob, 0); } else { vp8e_put_bool(bitbuf, prob, 1); vp8e_put_lit(bitbuf, new, 8); } } } } } return MPP_OK; } MPP_RET vp8e_calc_mv_prob(Vp8ePutBitBuf *bitbuf, RK_S32 (*curr)[2][19], RK_S32 (*prev)[2][19]) { RK_S32 i, j; RK_S32 prob, new, old; for (i = 0; i < 2; i++) { for (j = 0; j < 19; j++) { prob = mv_update_prob_tbl[i][j]; old = (RK_S32) (*prev)[i][j]; new = (RK_S32) (*curr)[i][j]; if (new == old) { vp8e_put_bool(bitbuf, prob, 0); } else { vp8e_put_bool(bitbuf, prob, 1); vp8e_put_lit(bitbuf, new >> 1, 7); } } } return MPP_OK; }