/****************************************************************************** * * Copyright (C) 2018 The Android Open Source Project * * 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. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ /** ****************************************************************************** * * @file ihevce_cabac.h * * @brief * This file contains encoder cabac engine related structures and * interface prototypes * * @author * ittiam * ****************************************************************************** */ #ifndef _IHEVCE_CABAC_H_ #define _IHEVCE_CABAC_H_ #include "ihevc_debug.h" #include "ihevc_macros.h" /*****************************************************************************/ /* Constant Macros */ /*****************************************************************************/ /** ******************************************************************************* @brief Bit precision of cabac engine; ******************************************************************************* */ #define CABAC_BITS 9 /** ******************************************************************************* @brief q format to account for the fractional bits encoded in cabac ******************************************************************************* */ #define CABAC_FRAC_BITS_Q 12 /** ******************************************************************************* @brief Enables bit-efficient chroma cbf signalling by peeking into cbfs of children nodes ******************************************************************************* */ #define CABAC_BIT_EFFICIENT_CHROMA_PARENT_CBF 1 /*****************************************************************************/ /* Function Macros */ /*****************************************************************************/ /** ******************************************************************************* @brief converts floating point number to CABAC_FRAC_BITS_Q q format and rounds the results to 16 bit integer ******************************************************************************* */ #define ROUND_Q12(x) ((UWORD16)(((x) * (1 << CABAC_FRAC_BITS_Q)) + 0.5)) /*****************************************************************************/ /* Enums */ /*****************************************************************************/ /** ******************************************************************************* @brief Enums for controlling the operating mode of cabac engine ******************************************************************************* */ typedef enum { /** in this mode, bits are encoded in the bit stream buffer */ CABAC_MODE_ENCODE_BITS = 0, /** in this mode, only num bits gen are computed but not put in the stream */ CABAC_MODE_COMPUTE_BITS = 1 } CABAC_OP_MODE; /*****************************************************************************/ /* Structures */ /*****************************************************************************/ /** ****************************************************************************** * @brief Cabac context for encoder ****************************************************************************** */ typedef struct cab_ctxt { /** * indicates if cabac encode works in put bits mode or bit compute mode * In puts bits mode, bitstream and cabac engine fields L,R etc are used * In bit compute mode, bitstream and cabac engine fields are not used */ CABAC_OP_MODE e_cabac_op_mode; /** * total bits estimated (for a cu) when mode is CABAC_MODE_COMPUTE_BITS * This is in q12 format to account for the fractional bits as well */ UWORD32 u4_bits_estimated_q12; /** * total texture bits estimated (for a cu) when mode is CABAC_MODE_COMPUTE_BITS * This is in q12 format to account for the fractional bits as well */ UWORD32 u4_texture_bits_estimated_q12; /** * total header bits estimated (for a cu) when mode is CABAC_MODE_COMPUTE_BITS * This is in q12 format to account for the fractional bits as well */ UWORD32 u4_header_bits_estimated_q12; UWORD32 u4_cbf_bits_q12; UWORD32 u4_true_tu_split_flag_q12; /*********************************************************************/ /* CABAC ENGINE related fields; not used in CABAC_MODE_COMPUTE_BITS */ /*********************************************************************/ /** cabac interval range R */ UWORD32 u4_range; /** cabac interval start L */ UWORD32 u4_low; /** bits generated during renormalization * A byte is put to stream/u4_out_standing_bytes from u4_low(L) when * u4_bits_gen exceeds 8 */ UWORD32 u4_bits_gen; /** bytes_outsanding; number of 0xFF bits that occur during renorm * These will be accumulated till the carry bit is knwon */ UWORD32 u4_out_standing_bytes; /*************************************************************************/ /* OUTPUT Bitstream related fields; not used in CABAC_MODE_COMPUTE_BITS */ /*************************************************************************/ /** points to start of stream buffer. */ UWORD8 *pu1_strm_buffer; /** * max bitstream size (in bytes). * Encoded stream shall not exceed this size. */ UWORD32 u4_max_strm_size; /** `* byte offset (w.r.t pu1_strm_buffer) where next byte would be written * Bitstream engine makes sure it would not corrupt data beyond * u4_max_strm_size bytes */ UWORD32 u4_strm_buf_offset; /** * signifies the number of consecutive zero bytes propogated from previous * word. It is used for emulation prevention byte insertion in the stream */ WORD32 i4_zero_bytes_run; /*********************************************************************/ /* CABAC context models */ /*********************************************************************/ /** All Context models stored in packed form pState[bits6-1] | MPS[bit0] */ UWORD8 au1_ctxt_models[IHEVC_CAB_CTXT_END]; /** *Cabac context for start of every row which is same as top right ctxt */ UWORD8 au1_ctxt_models_top_right[IHEVC_CAB_CTXT_END]; /** * copy of enable entropy coding sync flag in pps */ WORD8 i1_entropy_coding_sync_enabled_flag; /** * store the bitstream offset from which first slice data is generated by cabac */ UWORD32 u4_first_slice_start_offset; } cab_ctxt_t; /*****************************************************************************/ /* Globals */ /*****************************************************************************/ extern UWORD16 gau2_ihevce_cabac_bin_to_bits[64 * 2]; /*****************************************************************************/ /* Extern Function Declarations */ /*****************************************************************************/ WORD32 ihevce_cabac_reset(cab_ctxt_t *ps_cabac, bitstrm_t *ps_bitstrm, CABAC_OP_MODE e_cabac_op_mode); WORD32 ihevce_cabac_init( cab_ctxt_t *ps_cabac, bitstrm_t *ps_bitstrm, WORD32 slice_qp, WORD32 cabac_init_idc, CABAC_OP_MODE e_cabac_op_mode); WORD32 ihevce_cabac_put_byte(cab_ctxt_t *ps_cabac); /** ****************************************************************************** * * @brief Codes a bin based on probablilty and mps packed context model * * @par Description * 1. Apart from encoding bin, context model is updated as per state transition * 2. Range and Low renormalization is done based on bin and original state * 3. After renorm bistream is updated (if required) * * @param[inout] ps_cabac * pointer to cabac context (handle) * * @param[in] bin * bin(boolean) to be encoded * * @param[in] ctxt_index * index of cabac context model containing pState[bits6-1] | MPS[bit0] * * @return success or failure error code * ****************************************************************************** */ static INLINE WORD32 ihevce_cabac_encode_bin(cab_ctxt_t *ps_cabac, WORD32 bin, WORD32 ctxt_index) { UWORD32 u4_range = ps_cabac->u4_range; UWORD32 u4_low = ps_cabac->u4_low; UWORD32 u4_rlps; UWORD8 *pu1_ctxt_model = &ps_cabac->au1_ctxt_models[ctxt_index]; WORD32 state_mps = *pu1_ctxt_model; WORD32 shift; /* Sanity checks */ ASSERT((bin == 0) || (bin == 1)); ASSERT((ctxt_index >= 0) && (ctxt_index < IHEVC_CAB_CTXT_END)); ASSERT(state_mps < 128); if(CABAC_MODE_ENCODE_BITS == ps_cabac->e_cabac_op_mode) { ASSERT((u4_range >= 256) && (u4_range < 512)); /* Get the lps range from LUT based on quantized range and state */ u4_rlps = gau1_ihevc_cabac_rlps[state_mps >> 1][(u4_range >> 6) & 0x3]; u4_range -= u4_rlps; /* check if bin is mps or lps */ if((state_mps & 0x1) ^ bin) { /* lps path; L= L + R; R = RLPS */ u4_low += u4_range; u4_range = u4_rlps; } /*Compute bit always to populate the trace*/ /* increment bits generated based on state and bin encoded */ ps_cabac->u4_bits_estimated_q12 += gau2_ihevce_cabac_bin_to_bits[state_mps ^ bin]; /* update the context model from state transition LUT */ *pu1_ctxt_model = gau1_ihevc_next_state[(state_mps << 1) | bin]; /*****************************************************************/ /* Renormalization; calculate bits generated based on range(R) */ /* Note : 6 <= R < 512; R is 2 only for terminating encode */ /*****************************************************************/ GETRANGE(shift, u4_range); shift = 9 - shift; u4_low <<= shift; u4_range <<= shift; /* bits to be inserted in the bitstream */ ps_cabac->u4_bits_gen += shift; ps_cabac->u4_range = u4_range; ps_cabac->u4_low = u4_low; /* generate stream when a byte is ready */ if(ps_cabac->u4_bits_gen > CABAC_BITS) { return (ihevce_cabac_put_byte(ps_cabac)); } } else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */ { /* increment bits generated based on state and bin encoded */ ps_cabac->u4_bits_estimated_q12 += gau2_ihevce_cabac_bin_to_bits[state_mps ^ bin]; /* update the context model from state transition LUT */ *pu1_ctxt_model = gau1_ihevc_next_state[(state_mps << 1) | bin]; } return (IHEVCE_SUCCESS); } WORD32 ihevce_cabac_encode_bypass_bin(cab_ctxt_t *ps_cabac, WORD32 bin); WORD32 ihevce_cabac_encode_terminate(cab_ctxt_t *ps_cabac, WORD32 term_bin, WORD32 i4_end_of_sub_strm); /** ****************************************************************************** * * @brief Encodes a series of bypass bins (FLC bypass bins) * * @par Description * This function is more optimal than calling ihevce_cabac_encode_bypass_bin() * in a loop as cabac low, renorm and generating the stream (8bins at a time) * can be done in one operation * * @param[inout]ps_cabac * pointer to cabac context (handle) * * @param[in] u4_sym * syntax element to be coded (as FLC bins) * * @param[in] num_bins * This is the FLC length for u4_sym * * * @return success or failure error code * ****************************************************************************** */ static INLINE WORD32 ihevce_cabac_encode_bypass_bins(cab_ctxt_t *ps_cabac, UWORD32 u4_bins, WORD32 num_bins) { UWORD32 u4_range = ps_cabac->u4_range; WORD32 next_byte; WORD32 error = IHEVCE_SUCCESS; if(CABAC_MODE_ENCODE_BITS == ps_cabac->e_cabac_op_mode) { /* Sanity checks */ ASSERT((num_bins < 33) && (num_bins > 0)); ASSERT((u4_range >= 256) && (u4_range < 512)); /*Compute bit always to populate the trace*/ /* increment bits generated by num_bins */ ps_cabac->u4_bits_estimated_q12 += (num_bins << CABAC_FRAC_BITS_Q); /* Encode 8bins at a time and put in the bit-stream */ while(num_bins > 8) { num_bins -= 8; /* extract the leading 8 bins */ next_byte = (u4_bins >> num_bins) & 0xff; /* L = (L << 8) + (R * next_byte) */ ps_cabac->u4_low <<= 8; ps_cabac->u4_low += (next_byte * u4_range); ps_cabac->u4_bits_gen += 8; if(ps_cabac->u4_bits_gen > CABAC_BITS) { /* insert the leading byte of low into stream */ error |= ihevce_cabac_put_byte(ps_cabac); } } /* Update low with remaining bins and return */ next_byte = (u4_bins & ((1 << num_bins) - 1)); ps_cabac->u4_low <<= num_bins; ps_cabac->u4_low += (next_byte * u4_range); ps_cabac->u4_bits_gen += num_bins; if(ps_cabac->u4_bits_gen > CABAC_BITS) { /* insert the leading byte of low into stream */ error |= ihevce_cabac_put_byte(ps_cabac); } } else { /* increment bits generated by num_bins */ ps_cabac->u4_bits_estimated_q12 += (num_bins << CABAC_FRAC_BITS_Q); } return (error); } WORD32 ihevce_cabac_encode_tunary( cab_ctxt_t *ps_cabac, WORD32 sym, WORD32 c_max, WORD32 ctxt_index, WORD32 ctxt_shift, WORD32 ctxt_inc_max); WORD32 ihevce_cabac_encode_tunary_bypass(cab_ctxt_t *ps_cabac, WORD32 sym, WORD32 c_max); WORD32 ihevce_cabac_encode_egk(cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 k); WORD32 ihevce_cabac_encode_trunc_rice( cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 c_rice_param, WORD32 c_rice_max); WORD32 ihevce_cabac_flush(cab_ctxt_t *ps_cabac, WORD32 i4_end_of_sub_strm); WORD32 ihevce_cabac_ctxt_backup(cab_ctxt_t *ps_cabac); WORD32 ihevce_cabac_ctxt_row_init(cab_ctxt_t *ps_cabac); #endif /* _IHEVCE_CABAC_H_ */