/* * 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 "h265e_cabac" #include "mpp_mem.h" #include "mpp_common.h" #include "h265e_slice.h" #include "h265e_codec.h" #include "h265e_enctropy.h" #ifdef __GNUC__ /* GCCs builtin atomics */ #define CLZ32(id, x) id = (unsigned long)__builtin_clz(x) ^ 31 #elif defined(_MSC_VER) /* Windows atomic intrinsics */ #define CLZ32(id, x) _BitScanReverse(&id, x) #endif const RK_U8 g_lpsTable[64][4] = { { 128, 176, 208, 240 }, { 128, 167, 197, 227 }, { 128, 158, 187, 216 }, { 123, 150, 178, 205 }, { 116, 142, 169, 195 }, { 111, 135, 160, 185 }, { 105, 128, 152, 175 }, { 100, 122, 144, 166 }, { 95, 116, 137, 158 }, { 90, 110, 130, 150 }, { 85, 104, 123, 142 }, { 81, 99, 117, 135 }, { 77, 94, 111, 128 }, { 73, 89, 105, 122 }, { 69, 85, 100, 116 }, { 66, 80, 95, 110 }, { 62, 76, 90, 104 }, { 59, 72, 86, 99 }, { 56, 69, 81, 94 }, { 53, 65, 77, 89 }, { 51, 62, 73, 85 }, { 48, 59, 69, 80 }, { 46, 56, 66, 76 }, { 43, 53, 63, 72 }, { 41, 50, 59, 69 }, { 39, 48, 56, 65 }, { 37, 45, 54, 62 }, { 35, 43, 51, 59 }, { 33, 41, 48, 56 }, { 32, 39, 46, 53 }, { 30, 37, 43, 50 }, { 29, 35, 41, 48 }, { 27, 33, 39, 45 }, { 26, 31, 37, 43 }, { 24, 30, 35, 41 }, { 23, 28, 33, 39 }, { 22, 27, 32, 37 }, { 21, 26, 30, 35 }, { 20, 24, 29, 33 }, { 19, 23, 27, 31 }, { 18, 22, 26, 30 }, { 17, 21, 25, 28 }, { 16, 20, 23, 27 }, { 15, 19, 22, 25 }, { 14, 18, 21, 24 }, { 14, 17, 20, 23 }, { 13, 16, 19, 22 }, { 12, 15, 18, 21 }, { 12, 14, 17, 20 }, { 11, 14, 16, 19 }, { 11, 13, 15, 18 }, { 10, 12, 15, 17 }, { 10, 12, 14, 16 }, { 9, 11, 13, 15 }, { 9, 11, 12, 14 }, { 8, 10, 12, 14 }, { 8, 9, 11, 13 }, { 7, 9, 11, 12 }, { 7, 9, 10, 12 }, { 7, 8, 10, 11 }, { 6, 8, 9, 11 }, { 6, 7, 9, 10 }, { 6, 7, 8, 9 }, { 2, 2, 2, 2 } }; const RK_U8 g_nextState[128][2] = { { 2, 1 }, { 0, 3 }, { 4, 0 }, { 1, 5 }, { 6, 2 }, { 3, 7 }, { 8, 4 }, { 5, 9 }, { 10, 4 }, { 5, 11 }, { 12, 8 }, { 9, 13 }, { 14, 8 }, { 9, 15 }, { 16, 10 }, { 11, 17 }, { 18, 12 }, { 13, 19 }, { 20, 14 }, { 15, 21 }, { 22, 16 }, { 17, 23 }, { 24, 18 }, { 19, 25 }, { 26, 18 }, { 19, 27 }, { 28, 22 }, { 23, 29 }, { 30, 22 }, { 23, 31 }, { 32, 24 }, { 25, 33 }, { 34, 26 }, { 27, 35 }, { 36, 26 }, { 27, 37 }, { 38, 30 }, { 31, 39 }, { 40, 30 }, { 31, 41 }, { 42, 32 }, { 33, 43 }, { 44, 32 }, { 33, 45 }, { 46, 36 }, { 37, 47 }, { 48, 36 }, { 37, 49 }, { 50, 38 }, { 39, 51 }, { 52, 38 }, { 39, 53 }, { 54, 42 }, { 43, 55 }, { 56, 42 }, { 43, 57 }, { 58, 44 }, { 45, 59 }, { 60, 44 }, { 45, 61 }, { 62, 46 }, { 47, 63 }, { 64, 48 }, { 49, 65 }, { 66, 48 }, { 49, 67 }, { 68, 50 }, { 51, 69 }, { 70, 52 }, { 53, 71 }, { 72, 52 }, { 53, 73 }, { 74, 54 }, { 55, 75 }, { 76, 54 }, { 55, 77 }, { 78, 56 }, { 57, 79 }, { 80, 58 }, { 59, 81 }, { 82, 58 }, { 59, 83 }, { 84, 60 }, { 61, 85 }, { 86, 60 }, { 61, 87 }, { 88, 60 }, { 61, 89 }, { 90, 62 }, { 63, 91 }, { 92, 64 }, { 65, 93 }, { 94, 64 }, { 65, 95 }, { 96, 66 }, { 67, 97 }, { 98, 66 }, { 67, 99 }, { 100, 66 }, { 67, 101 }, { 102, 68 }, { 69, 103 }, { 104, 68 }, { 69, 105 }, { 106, 70 }, { 71, 107 }, { 108, 70 }, { 71, 109 }, { 110, 70 }, { 71, 111 }, { 112, 72 }, { 73, 113 }, { 114, 72 }, { 73, 115 }, { 116, 72 }, { 73, 117 }, { 118, 74 }, { 75, 119 }, { 120, 74 }, { 75, 121 }, { 122, 74 }, { 75, 123 }, { 124, 76 }, { 77, 125 }, { 124, 76 }, { 77, 125 }, { 126, 126 }, { 127, 127 } }; RK_U8 sbacInit(RK_S32 qp, RK_S32 initValue) { RK_S32 slope = (initValue >> 4) * 5 - 45; RK_S32 offset = ((initValue & 15) << 3) - 16; RK_S32 initState = MPP_MIN(MPP_MAX(1, (((slope * qp) >> 4) + offset)), 126); RK_U32 mpState = (initState >= 64); RK_U8 m_state = ((mpState ? (initState - 64) : (63 - initState)) << 1) + mpState; return m_state; } static void initBuffer(H265eContextModel_t* contextModel, SliceType sliceType, RK_U8 cabacIntFlag, RK_S32 qp, RK_U8* ctxModel, RK_S32 size) { RK_S8 initType = 0; RK_S32 n = 0; h265e_dbg_skip("sliceType = %d", sliceType); if (sliceType == I_SLICE) initType = 0; else if (sliceType == P_SLICE) initType = cabacIntFlag ? 2 : 1; else initType = cabacIntFlag ? 1 : 2; ctxModel += (2 - initType) * size; for (n = 0; n < size; n++) { contextModel[n].m_state = sbacInit(qp, ctxModel[n]); //mpp_log("contextModel[%d].m_state = %d", n, contextModel[n].m_state); contextModel[n].bBinsCoded = 0; } } void h265e_reset_enctropy(void *slice_ctx) { H265eSlice *slice = (H265eSlice *)slice_ctx; RK_U8 cabacInitFlag = slice->m_cabacInitFlag; RK_S32 qp = slice->m_sliceQp; SliceType sliceType = slice->m_sliceType; h265e_dbg_func("enter\n"); initBuffer(&slice->m_contextModels[OFF_SPLIT_FLAG_CTX], sliceType, cabacInitFlag, qp, (RK_U8*)INIT_SPLIT_FLAG, NUM_SPLIT_FLAG_CTX); initBuffer(&slice->m_contextModels[OFF_SKIP_FLAG_CTX], sliceType, cabacInitFlag, qp, (RK_U8*)INIT_SKIP_FLAG, NUM_SKIP_FLAG_CTX); initBuffer(&slice->m_contextModels[OFF_MERGE_FLAG_EXT_CTX], sliceType, cabacInitFlag, qp, (RK_U8*)INIT_MERGE_FLAG_EXT, NUM_MERGE_FLAG_EXT_CTX); initBuffer(&slice->m_contextModels[OFF_MERGE_IDX_EXT_CTX], sliceType, cabacInitFlag, qp, (uint8_t*)INIT_MERGE_IDX_EXT, NUM_MERGE_IDX_EXT_CTX); h265e_dbg_func("leave\n"); } void h265e_cabac_resetBits(H265eCabacCtx *cabac_ctx) { h265e_dbg_func("enter\n"); cabac_ctx->m_low = 0; cabac_ctx->m_bitsLeft = -12; cabac_ctx->m_numBufferedBytes = 0; cabac_ctx->m_bufferedByte = 0xff; cabac_ctx->m_fracBits = 0; h265e_dbg_func("leave\n"); } void h265e_cabac_start(H265eCabacCtx *cabac_ctx) { h265e_dbg_func("enter\n"); cabac_ctx->m_low = 0; cabac_ctx->m_range = 510; cabac_ctx->m_bitsLeft = -12; cabac_ctx->m_numBufferedBytes = 0; cabac_ctx->m_bufferedByte = 0xff; } void h265e_cabac_init(H265eCabacCtx *cabac_ctx, MppWriteCtx * bitIf) { h265e_dbg_func("enter\n"); cabac_ctx->m_bitIf = bitIf; h265e_cabac_start(cabac_ctx); h265e_dbg_func("leave\n"); } void h265e_cabac_writeOut(H265eCabacCtx *cabac_ctx) { MppWriteCtx* s = cabac_ctx->m_bitIf; RK_U32 leadByte = cabac_ctx->m_low >> (13 + cabac_ctx->m_bitsLeft); RK_U32 low_mask = (RK_U32)(~0) >> (11 + 8 - cabac_ctx->m_bitsLeft); h265e_dbg_func("enter\n"); cabac_ctx->m_bitsLeft -= 8; cabac_ctx->m_low &= low_mask; if (leadByte == 0xff) { cabac_ctx->m_numBufferedBytes++; } else { RK_U32 numBufferedBytes = cabac_ctx->m_numBufferedBytes; if (numBufferedBytes > 0) { RK_U32 carry = leadByte >> 8; RK_U32 byteTowrite = cabac_ctx->m_bufferedByte + carry; mpp_writer_put_bits(s, byteTowrite, 8); h265e_dbg_skip("byteTowrite = %x", byteTowrite); byteTowrite = (0xff + carry) & 0xff; while (numBufferedBytes > 1) { h265e_dbg_skip("byteTowrite = %x", byteTowrite); mpp_writer_put_bits(s, byteTowrite, 8); numBufferedBytes--; } } cabac_ctx->m_numBufferedBytes = 1; cabac_ctx->m_bufferedByte = (uint8_t)leadByte; } h265e_dbg_func("leave\n"); } /** * \brief Encode bin * * \param binValue bin value * \param rcCtxModel context model */ void h265e_cabac_encodeBin(H265eCabacCtx *cabac_ctx, H265eContextModel_t *ctxModel, RK_U32 binValue) { RK_U32 mstate = ctxModel->m_state; h265e_dbg_func("enter\n"); // mpp_log("before m_low %d ctxModel.m_state %d m_range %d \n", cabac_ctx->m_low, ctxModel->m_state,cabac_ctx->m_range); ctxModel->m_state = sbacNext(mstate, binValue); ctxModel->bBinsCoded = 1; RK_U32 range = cabac_ctx->m_range; RK_U32 state = sbacGetState(mstate); RK_U32 lps = g_lpsTable[state][((uint8_t)range >> 6)]; range -= lps; // mpp_log("ctxModel.m_state %d binValue %d \n", ctxModel->m_state, binValue); // assert(lps >= 2); RK_S32 numBits = (RK_U32)(range - 256) >> 31; RK_U32 low = cabac_ctx->m_low; // NOTE: MPS must be LOWEST bit in mstate // assert(((binValue ^ mstate) & 1) == (binValue != sbacGetMps(mstate))); if ((binValue ^ mstate) & 1) { unsigned long idx; CLZ32(idx, lps); // assert(state != 63 || idx == 1); numBits = 8 - idx; if (state >= 63) numBits = 6; // assert(numBits <= 6); low += range; range = lps; } cabac_ctx->m_low = (low << numBits); cabac_ctx->m_range = (range << numBits); cabac_ctx->m_bitsLeft += numBits; // mpp_log("after m_low %d ctxModel.m_state %d m_range %d \n", cabac_ctx->m_low, ctxModel->m_state,cabac_ctx->m_range); if (cabac_ctx->m_bitsLeft >= 0) { h265e_cabac_writeOut(cabac_ctx); } h265e_dbg_func("leave\n"); } void h265e_cabac_encodeBinTrm(H265eCabacCtx *cabac_ctx, RK_U32 binValue) { h265e_dbg_func("enter\n"); // mpp_log("encodeBinTrm m_range %d binValue %d \n", cabac_ctx->m_range, binValue); cabac_ctx->m_range -= 2; if (binValue) { cabac_ctx->m_low += cabac_ctx->m_range; cabac_ctx->m_low <<= 7; cabac_ctx->m_range = 2 << 7; cabac_ctx->m_bitsLeft += 7; } else if (cabac_ctx->m_range >= 256) { return; } else { cabac_ctx->m_low <<= 1; cabac_ctx->m_range <<= 1; cabac_ctx->m_bitsLeft++; } if (cabac_ctx->m_bitsLeft >= 0) { h265e_cabac_writeOut(cabac_ctx); } h265e_dbg_func("leave\n"); } void h265e_cabac_finish(H265eCabacCtx *cabac_ctx) { MppWriteCtx* s = cabac_ctx->m_bitIf; h265e_dbg_func("enter\n"); if (cabac_ctx->m_low >> (21 + cabac_ctx->m_bitsLeft)) { mpp_writer_put_bits(s, cabac_ctx->m_bufferedByte + 1, 8); while (cabac_ctx->m_numBufferedBytes > 1) { mpp_writer_put_bits(s, 0, 8); cabac_ctx->m_numBufferedBytes--; } cabac_ctx->m_low -= 1 << (21 + cabac_ctx->m_bitsLeft); } else { if (cabac_ctx->m_numBufferedBytes > 0) { mpp_writer_put_bits(s, cabac_ctx->m_bufferedByte , 8); } while (cabac_ctx->m_numBufferedBytes > 1) { mpp_writer_put_bits(s, 0xff , 8); cabac_ctx->m_numBufferedBytes--; } } mpp_writer_put_bits(s, cabac_ctx->m_low >> 8 , 13 + cabac_ctx->m_bitsLeft); h265e_dbg_func("leave\n"); } void h265e_cabac_flush(H265eCabacCtx *cabac_ctx) { MppWriteCtx* s = cabac_ctx->m_bitIf; h265e_dbg_func("enter\n"); h265e_cabac_encodeBinTrm(cabac_ctx, 1); h265e_cabac_finish(cabac_ctx); mpp_writer_put_bits(s, 1, 1); mpp_writer_align_zero(s); h265e_cabac_start(cabac_ctx); h265e_dbg_func("leave\n"); }