C++程序  |  915行  |  30.39 KB

/******************************************************************************
 *
 * 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.c
*
* @brief
*  This file contains function definitions related to bitstream generation
*
* @author
*  ittiam
*
* @List of Functions
*  ihevce_cabac_reset()
*  ihevce_cabac_init()
*  ihevce_cabac_put_byte()
*  ihevce_cabac_encode_bin()
*  ihevce_cabac_encode_bypass_bin()
*  ihevce_cabac_encode_terminate()
*  ihevce_cabac_encode_tunary()
*  ihevce_cabac_encode_tunary_bypass()
*  ihevce_cabac_encode_bypass_bins()
*  ihevce_cabac_encode_egk()
*  ihevce_cabac_encode_trunc_rice()
*  ihevce_cabac_encode_trunc_rice_ctxt()
*  ihevce_cabac_flush()
*  ihevce_cabac_ctxt_backup()
*  ihevce_cabac_ctxt_row_init()
*
*******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/
/* System include files */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <math.h>

/* User include files */
#include "ihevc_typedefs.h"
#include "ihevc_debug.h"
#include "ihevc_macros.h"
#include "ihevc_platform_macros.h"
#include "ihevc_cabac_tables.h"

#include "ihevce_defs.h"
#include "ihevce_error_codes.h"
#include "ihevce_bitstream.h"
#include "ihevce_cabac.h"

#define TEST_CABAC_BITESTIMATE 0

/*****************************************************************************/
/* Function Definitions                                                      */
/*****************************************************************************/

/**
******************************************************************************
*
*  @brief Resets the encoder cabac engine
*
*  @par   Description
*  This routine needs to be called at start of dependent slice encode
*
*  @param[inout]   ps_cabac_ctxt
*  pointer to cabac context (handle)
*
*  @param[in]   ps_bitstrm
*  pointer to bitstream context (handle)
*
*  @param[in]   e_cabac_op_mode
*  opertaing mode of cabac; put bits / compute bits mode @sa CABAC_OP_MODE
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32
    ihevce_cabac_reset(cab_ctxt_t *ps_cabac, bitstrm_t *ps_bitstrm, CABAC_OP_MODE e_cabac_op_mode)
{
    /* Sanity checks */
    ASSERT(ps_cabac != NULL);
    ASSERT(
        (e_cabac_op_mode == CABAC_MODE_ENCODE_BITS) ||
        (e_cabac_op_mode == CABAC_MODE_COMPUTE_BITS));

    ps_cabac->e_cabac_op_mode = e_cabac_op_mode;

    if(CABAC_MODE_ENCODE_BITS == e_cabac_op_mode)
    {
        ASSERT(ps_bitstrm != NULL);

        /* Bitstream context initialization */
        ps_cabac->pu1_strm_buffer = ps_bitstrm->pu1_strm_buffer;
        ps_cabac->u4_max_strm_size = ps_bitstrm->u4_max_strm_size;
        /* When entropy sync is enabled start form fixed offset from point
         * where slice header extension has ended to handle emulation prevention
         *  bytes during insertion of slice offset at end of frame */
        if(1 == ps_cabac->i1_entropy_coding_sync_enabled_flag)
        {
            ps_cabac->u4_strm_buf_offset = ps_cabac->u4_first_slice_start_offset;
        }
        else
        {
            ps_cabac->u4_strm_buf_offset = ps_bitstrm->u4_strm_buf_offset;
        }
        ps_cabac->i4_zero_bytes_run = ps_bitstrm->i4_zero_bytes_run;

        /* cabac engine initialization */
        ps_cabac->u4_low = 0;
        ps_cabac->u4_range = 510;
        ps_cabac->u4_bits_gen = 0;
        ps_cabac->u4_out_standing_bytes = 0;
    }
    else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */
    {
        /* reset the bits estimated */
        ps_cabac->u4_bits_estimated_q12 = 0;

        /* reset the texture bits estimated */
        ps_cabac->u4_texture_bits_estimated_q12 = 0;

        /* Setting range to 0 switches off AEV_TRACE in compute bits mode */
        ps_cabac->u4_range = 0;
    }

    return (IHEVCE_SUCCESS);
}

/**
******************************************************************************
*
*  @brief Initializes the encoder cabac engine
*
*  @par   Description
*  This routine needs to be called at start of slice/frame encode
*
*  @param[inout]   ps_cabac_ctxt
*  pointer to cabac context (handle)
*
*  @param[in]   ps_bitstrm
*  pointer to bitstream context (handle)
*
*  @param[in]   qp
*  current slice qp
*
*  @param[in]   cabac_init_idc
*  current slice init idc (range - [0- 2])*
*
*  @param[in]   e_cabac_op_mode
*  opertaing mode of cabac; put bits / compute bits mode @sa CABAC_OP_MODE
*
*  @return      success or failure error code
*
******************************************************************************
*/
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)
{
    /* Sanity checks */
    ASSERT(ps_cabac != NULL);
    ASSERT((slice_qp >= 0) && (slice_qp < IHEVC_MAX_QP));
    ASSERT((cabac_init_idc >= 0) && (cabac_init_idc < 3));
    ASSERT(
        (e_cabac_op_mode == CABAC_MODE_ENCODE_BITS) ||
        (e_cabac_op_mode == CABAC_MODE_COMPUTE_BITS));

    ps_cabac->e_cabac_op_mode = e_cabac_op_mode;

    if(CABAC_MODE_ENCODE_BITS == e_cabac_op_mode)
    {
        ASSERT(ps_bitstrm != NULL);

        /* Bitstream context initialization */
        ps_cabac->pu1_strm_buffer = ps_bitstrm->pu1_strm_buffer;
        ps_cabac->u4_max_strm_size = ps_bitstrm->u4_max_strm_size;
        /* When entropy sync is enabled start form fixed offset from point
         * where slice header extension has ended to handle emulation prevention
         *  bytes during insertion of slice offset at end of frame */
        if(1 == ps_cabac->i1_entropy_coding_sync_enabled_flag)
        {
            ps_cabac->u4_strm_buf_offset = ps_cabac->u4_first_slice_start_offset;
        }
        else
        {
            ps_cabac->u4_strm_buf_offset = ps_bitstrm->u4_strm_buf_offset;
        }
        ps_cabac->i4_zero_bytes_run = ps_bitstrm->i4_zero_bytes_run;

        /* cabac engine initialization */
        ps_cabac->u4_low = 0;
        ps_cabac->u4_range = 510;
        ps_cabac->u4_bits_gen = 0;
        ps_cabac->u4_out_standing_bytes = 0;

        /* reset the bits estimated */
        ps_cabac->u4_bits_estimated_q12 = 0;

        /* reset the texture bits estimated */
        ps_cabac->u4_texture_bits_estimated_q12 = 0;
    }
    else /* (CABAC_MODE_COMPUTE_BITS == e_cabac_op_mode) */
    {
        /* reset the bits estimated */
        ps_cabac->u4_bits_estimated_q12 = 0;

        /* reset the texture bits estimated */
        ps_cabac->u4_texture_bits_estimated_q12 = 0;

        /* Setting range to 0 switches off AEV_TRACE in compute bits mode */
        ps_cabac->u4_range = 0;
    }

    /* cabac context initialization based on init idc and slice qp */
    COPY_CABAC_STATES(
        ps_cabac->au1_ctxt_models,
        &gau1_ihevc_cab_ctxts[cabac_init_idc][slice_qp][0],
        IHEVC_CAB_CTXT_END);

    return (IHEVCE_SUCCESS);
}

/**
******************************************************************************
*
*  @brief Puts new byte (and outstanding bytes) into bitstream after cabac
*         renormalization
*
*  @par   Description
*  1. Extract the leading byte of low(L)
*  2. If leading byte=0xff increment outstanding bytes and return
*     (as the actual bits depend on carry propogation later)
*  3. If leading byte is not 0xff check for any carry propogation
*  4. Insert the carry (propogated in previous byte) along with outstanding
*     bytes (if any) and leading byte
*
*
*  @param[inout]   ps_cabac
*  pointer to cabac context (handle)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_put_byte(cab_ctxt_t *ps_cabac)
{
    UWORD32 u4_low = ps_cabac->u4_low;
    UWORD32 u4_bits_gen = ps_cabac->u4_bits_gen;
    WORD32 lead_byte = u4_low >> (u4_bits_gen + CABAC_BITS - 8);

    /* Sanity checks */
    ASSERT((ps_cabac->u4_range >= 256) && (ps_cabac->u4_range < 512));
    ASSERT((u4_bits_gen >= 8));

    /* update bits generated and low after extracting leading byte */
    u4_bits_gen -= 8;
    ps_cabac->u4_low &= ((1 << (CABAC_BITS + u4_bits_gen)) - 1);
    ps_cabac->u4_bits_gen = u4_bits_gen;

    /************************************************************************/
    /* 1. Extract the leading byte of low(L)                                */
    /* 2. If leading byte=0xff increment outstanding bytes and return       */
    /*      (as the actual bits depend on carry propogation later)          */
    /* 3. If leading byte is not 0xff check for any carry propogation       */
    /* 4. Insert the carry (propogated in previous byte) along with         */
    /*    outstanding bytes (if any) and leading byte                       */
    /************************************************************************/
    if(lead_byte == 0xff)
    {
        /* actual bits depend on carry propogration     */
        ps_cabac->u4_out_standing_bytes++;
        return (IHEVCE_SUCCESS);
    }
    else
    {
        /* carry = 1 => putbit(1); carry propogated due to L renorm */
        WORD32 carry = (lead_byte >> 8) & 0x1;
        UWORD8 *pu1_strm_buf = ps_cabac->pu1_strm_buffer;
        UWORD32 u4_strm_buf_offset = ps_cabac->u4_strm_buf_offset;
        WORD32 zero_run = ps_cabac->i4_zero_bytes_run;
        UWORD32 u4_out_standing_bytes = ps_cabac->u4_out_standing_bytes;

        /*********************************************************************/
        /* Bitstream overflow check                                          */
        /* NOTE: corner case of epb bytes (max 2 for 32bit word) not handled */
        /*********************************************************************/
        if((u4_strm_buf_offset + u4_out_standing_bytes + 1) >= ps_cabac->u4_max_strm_size)
        {
            /* return without corrupting the buffer beyond its size */
            return (IHEVCE_BITSTREAM_BUFFER_OVERFLOW);
        }

        /*********************************************************************/
        /*        Insert the carry propogated in previous byte               */
        /*                                                                   */
        /* Note : Do not worry about corruption into slice header align byte */
        /*        This is because the first bin cannot result in overflow    */
        /*********************************************************************/
        if(carry)
        {
            /* CORNER CASE: if the previous data is 0x000003, then EPB will be inserted
            and the data will become 0x00000303 and if the carry is present, it will
            be added with the last byte and it will become 0x00000304 which is not correct
            as per standard*/
            /* so check for previous four bytes and if it is equal to 0x00000303
            then subtract u4_strm_buf_offset by 1 */
            if(pu1_strm_buf[u4_strm_buf_offset - 1] == 0x03 &&
               pu1_strm_buf[u4_strm_buf_offset - 2] == 0x03 &&
               pu1_strm_buf[u4_strm_buf_offset - 3] == 0x00 &&
               pu1_strm_buf[u4_strm_buf_offset - 4] == 0x00)
            {
                u4_strm_buf_offset -= 1;
            }
            /* previous byte carry add will not result in overflow to        */
            /* u4_strm_buf_offset - 2 as we track 0xff as outstanding bytes  */
            pu1_strm_buf[u4_strm_buf_offset - 1] += carry;
            zero_run = 0;
        }

        /*        Insert outstanding bytes (if any)         */
        while(u4_out_standing_bytes)
        {
            UWORD8 u1_0_or_ff = carry ? 0 : 0xFF;

            PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, u1_0_or_ff, zero_run);

            u4_out_standing_bytes--;
        }
        ps_cabac->u4_out_standing_bytes = 0;

        /*        Insert the leading byte                   */
        lead_byte &= 0xFF;
        PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, lead_byte, zero_run);

        /* update the state variables and return success */
        ps_cabac->u4_strm_buf_offset = u4_strm_buf_offset;
        ps_cabac->i4_zero_bytes_run = zero_run;
        return (IHEVCE_SUCCESS);
    }
}

/**
******************************************************************************
*
*  @brief Codes a bypass bin (equi probable 0 / 1)
*
*  @par   Description
*  After encoding bypass bin, bits gen incremented by 1 and bitstream generated
*
*  @param[inout]  ps_cabac : pointer to cabac context (handle)
*
*  @param[in]   bin :  bypass bin(0/1) to be encoded
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_encode_bypass_bin(cab_ctxt_t *ps_cabac, WORD32 bin)
{
    UWORD32 u4_range = ps_cabac->u4_range;
    UWORD32 u4_low = ps_cabac->u4_low;

    if(CABAC_MODE_ENCODE_BITS == ps_cabac->e_cabac_op_mode)
    {
        /* Sanity checks */
        ASSERT((u4_range >= 256) && (u4_range < 512));
        ASSERT((bin == 0) || (bin == 1));

        /*Compute bit always to populate the trace*/
        /* increment bits generated by 1 */
        ps_cabac->u4_bits_estimated_q12 += (1 << CABAC_FRAC_BITS_Q);

        u4_low <<= 1;
        /* add range if bin is 1 */
        if(bin)
        {
            u4_low += u4_range;
        }

        /* 1 bit to be inserted in the bitstream */
        ps_cabac->u4_bits_gen++;
        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 by 1 */
        ps_cabac->u4_bits_estimated_q12 += (1 << CABAC_FRAC_BITS_Q);
    }

    return (IHEVCE_SUCCESS);
}

/**
******************************************************************************
*
*  @brief Codes a terminate bin (1:terminate 0:do not terminate)
*
*  @par   Description
*  After encoding bypass bin, bits gen incremented by 1 and bitstream generated
*
*  @param[inout]  ps_cabac : pointer to cabac context (handle)
*
*  @param[in]   term_bin : (1:terminate 0:do not terminate)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32
    ihevce_cabac_encode_terminate(cab_ctxt_t *ps_cabac, WORD32 term_bin, WORD32 i4_end_of_sub_strm)
{
    UWORD32 u4_range = ps_cabac->u4_range;
    UWORD32 u4_low = ps_cabac->u4_low;
    UWORD32 u4_rlps;
    WORD32 shift;
    WORD32 error = IHEVCE_SUCCESS;

    /* Sanity checks */
    ASSERT((u4_range >= 256) && (u4_range < 512));
    ASSERT((term_bin == 0) || (term_bin == 1));

    /*  term_bin = 1 has lps range = 2 */
    u4_rlps = 2;
    u4_range -= u4_rlps;

    /* if terminate L is incremented by curR and R=2 */
    if(term_bin)
    {
        /* lps path;  L= L + R; R = RLPS */
        u4_low += u4_range;
        u4_range = u4_rlps;
    }

    /*****************************************************************/
    /* 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)
    {
        error = ihevce_cabac_put_byte(ps_cabac);
    }

    if(term_bin)
    {
        ihevce_cabac_flush(ps_cabac, i4_end_of_sub_strm);
    }

    /*Compute bit always to populate the trace*/
    ps_cabac->u4_bits_estimated_q12 += gau2_ihevce_cabac_bin_to_bits[(62 << 1) | term_bin];

    return (error);
}

/**
******************************************************************************
*
*  @brief Encodes a truncated unary symbol associated with context model(s)
*
*  @par   Description
*  Does binarization of tunary symbol as per sec 9.3.2.2 and does the cabac
*  encoding of each bin. This is used for computing symbols like qp_delta,
*  last_sig_coeff_prefix_x, last_sig_coeff_prefix_y.
*
*  The context models associated with each bin is computed as :
*   current bin context = "base context idx" + (bin_idx >> shift)
*  where
*   1. "base context idx" is the base index for the syntax element
*   2. "bin_idx" is the current bin index of the unary code
*   3. "shift" is the shift factor associated with this syntax element
*
*  @param[inout]ps_cabac
*   pointer to cabac context (handle)
*
*  @param[in]   sym
*   syntax element to be coded as truncated unary bins
*
*  @param[in]   c_max
*   maximum value of sym (required for tunary binarization)
*
*  @param[in]   ctxt_index
*   base context model index for this syntax element
*
*  @param[in]   ctxt_shift
*   shift factor for context increments associated with this syntax element
*
*  @param[in]   ctxt_inc_max
*   max value of context increment beyond which all bins will use same ctxt
*
*  @return      success or failure error code
*
******************************************************************************
*/
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 bin_ctxt, i;
    WORD32 error = IHEVCE_SUCCESS;

    /* Sanity checks */
    ASSERT(c_max > 0);
    ASSERT((sym <= c_max) && (sym >= 0));
    ASSERT((ctxt_index >= 0) && (ctxt_index < IHEVC_CAB_CTXT_END));
    ASSERT((ctxt_index + (c_max >> ctxt_shift)) < IHEVC_CAB_CTXT_END);

    /* Special case of sym= 0 */
    if(0 == sym)
    {
        return (ihevce_cabac_encode_bin(ps_cabac, 0, ctxt_index));
    }

    /* write '1' bins  */
    for(i = 0; i < sym; i++)
    {
        /* TODO: encode bin to be inlined later */
        bin_ctxt = ctxt_index + MIN((i >> ctxt_shift), ctxt_inc_max);
        error |= ihevce_cabac_encode_bin(ps_cabac, 1, bin_ctxt);
    }

    /* write terminating 0 bin */
    if(sym < c_max)
    {
        /* TODO: encode bin to be inlined later */
        bin_ctxt = ctxt_index + MIN((i >> ctxt_shift), ctxt_inc_max);
        error |= ihevce_cabac_encode_bin(ps_cabac, 0, bin_ctxt);
    }

    return (error);
}

/**
******************************************************************************
*
*  @brief Encodes a syntax element as truncated unary bypass bins
*
*  @par   Description
*  Does binarization of tunary symbol as per sec 9.3.2.2 and does the cabac
*  encoding of each bin. This is used for computing symbols like merge_idx,
*  mpm_idx etc
*
*  @param[inout]ps_cabac
*   pointer to cabac context (handle)
*
*  @param[in]   sym
*   syntax element to be coded as truncated unary bins
*
*  @param[in]   c_max
*   maximum value of sym (required for tunary binarization)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_encode_tunary_bypass(cab_ctxt_t *ps_cabac, WORD32 sym, WORD32 c_max)
{
    WORD32 error = IHEVCE_SUCCESS;
    WORD32 length;
    WORD32 u4_bins;

    /* Sanity checks */
    ASSERT(c_max > 0);
    ASSERT((sym <= c_max) && (sym >= 0));

    if(sym < c_max)
    {
        /* unary code with (sym) '1's and terminating '0' bin */
        length = (sym + 1);
        u4_bins = (1 << length) - 2;
    }
    else
    {
        /* tunary code with (sym) '1's */
        length = sym;
        u4_bins = (1 << length) - 1;
    }

    /* Encode the tunary binarized code as bypass bins */
    error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_bins, length);

    return (error);
}

/**
******************************************************************************
*
*  @brief Encodes a syntax element as kth order Exp-Golomb code (EGK)
*
*  @par   Description
*  Does binarization of symbol as per sec 9.3.2.4  kth order Exp-Golomb(EGk)
*  process and encodes the resulting bypass bins
*
*  @param[inout]ps_cabac
*   pointer to cabac context (handle)
*
*  @param[in]   u4_sym
*   syntax element to be coded as EGK
*
*  @param[in]   k
*   order of EGk
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_encode_egk(cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 k)
{
    WORD32 num_bins, unary_length;
    UWORD32 u4_sym_shiftk_plus1, u4_egk, u4_unary_bins;

    WORD32 error = IHEVCE_SUCCESS;

    /* Sanity checks */
    ASSERT((k >= 0));
    /* ASSERT(u4_sym >= (UWORD32)(1 << k)); */

    /************************************************************************/
    /* shift symbol by k bits to find unary code prefix (111110)            */
    /* Use GETRANGE to elminate the while loop in sec 9.3.2.4 of HEVC spec  */
    /************************************************************************/
    u4_sym_shiftk_plus1 = (u4_sym >> k) + 1;
    /* GETRANGE(unary_length, (u4_sym_shiftk_plus1 + 1)); */
    GETRANGE(unary_length, u4_sym_shiftk_plus1);

    /* unary code with (unary_length-1) '1's and terminating '0' bin */
    u4_unary_bins = (1 << unary_length) - 2;

    /* insert the symbol prefix of (unary lenght - 1)  bins */
    u4_egk = (u4_unary_bins << (unary_length - 1)) |
             (u4_sym_shiftk_plus1 & ((1 << (unary_length - 1)) - 1));

    /* insert last k bits of symbol in the end */
    u4_egk = (u4_egk << k) | (u4_sym & ((1 << k) - 1));

    /* length of the code = 2 *(unary_length - 1) + 1 + k */
    num_bins = (2 * unary_length) - 1 + k;

    /* Encode the egk binarized code as bypass bins */
    error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_egk, num_bins);

    return (error);
}

/**
******************************************************************************
*
*  @brief Encodes a syntax element as truncated rice code (TR)
*
*  @par   Description
*  Does binarization of symbol as per sec 9.3.2.3 Truncated Rice(TR)
*  binarization process and encodes the resulting bypass bins
*  This function ise used for coeff_abs_level_remaining coding when
*  level is less than c_rice_max
*
*  @param[inout]ps_cabac
*   pointer to cabac context (handle)
*
*  @param[in]   u4_sym
*   syntax element to be coded as truncated rice code
*
*  @param[in]   c_rice_param
*    shift factor for truncated unary prefix coding of (u4_sym >> c_rice_param)
*
*  @param[in]   c_rice_max
*    max symbol val below which a suffix is coded as (u4_sym%(1<<c_rice_param))
*    This is currently (4 << c_rice_param) for coeff_abs_level_remaining
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_encode_trunc_rice(
    cab_ctxt_t *ps_cabac, UWORD32 u4_sym, WORD32 c_rice_param, WORD32 c_rice_max)
{
    WORD32 num_bins, unary_length, u4_unary_bins;
    UWORD32 u4_tr;

    WORD32 error = IHEVCE_SUCCESS;

    (void)c_rice_max;
    /* Sanity checks */
    ASSERT((c_rice_param >= 0));
    ASSERT((UWORD32)c_rice_max > u4_sym);

    /************************************************************************/
    /* shift symbol by c_rice_param bits to find unary code prefix (111.10) */
    /************************************************************************/
    unary_length = (u4_sym >> c_rice_param) + 1;

    /* unary code with (unary_length-1) '1's and terminating '0' bin */
    u4_unary_bins = (1 << unary_length) - 2;

    /* insert last c_rice_param bits of symbol in the end */
    u4_tr = (u4_unary_bins << c_rice_param) | (u4_sym & ((1 << c_rice_param) - 1));

    /* length of the code */
    num_bins = unary_length + c_rice_param;

    /* Encode the tr binarized code as bypass bins */
    error = ihevce_cabac_encode_bypass_bins(ps_cabac, u4_tr, num_bins);

    return (error);
}

/**
******************************************************************************
*
*  @brief Flushes the cabac encoder engine as per section 9.3.4 figure 9-12
*
*  @par   Description
*
*
*  @param[inout]   ps_cabac
*  pointer to cabac context (handle)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_flush(cab_ctxt_t *ps_cabac, WORD32 i4_end_of_sub_strm)
{
    UWORD32 u4_low = ps_cabac->u4_low;
    UWORD32 u4_bits_gen = ps_cabac->u4_bits_gen;

    UWORD8 *pu1_strm_buf = ps_cabac->pu1_strm_buffer;
    UWORD32 u4_strm_buf_offset = ps_cabac->u4_strm_buf_offset;
    WORD32 zero_run = ps_cabac->i4_zero_bytes_run;
    UWORD32 u4_out_standing_bytes = ps_cabac->u4_out_standing_bytes;

    (void)i4_end_of_sub_strm;
    /************************************************************************/
    /* Insert the carry (propogated in previous byte) along with            */
    /* outstanding bytes (if any) and flush remaining bits                  */
    /************************************************************************/

    //TODO: Review this function
    {
        /* carry = 1 => putbit(1); carry propogated due to L renorm */
        WORD32 carry = (u4_low >> (u4_bits_gen + CABAC_BITS)) & 0x1;
        WORD32 last_byte;
        WORD32 bits_left;
        WORD32 rem_bits;

        /*********************************************************************/
        /* Bitstream overflow check                                          */
        /* NOTE: corner case of epb bytes (max 2 for 32bit word) not handled */
        /*********************************************************************/
        if((u4_strm_buf_offset + u4_out_standing_bytes + 1) >= ps_cabac->u4_max_strm_size)
        {
            /* return without corrupting the buffer beyond its size */
            return (IHEVCE_BITSTREAM_BUFFER_OVERFLOW);
        }

        if(carry)
        {
            /* CORNER CASE: if the previous data is 0x000003, then EPB will be inserted
            and the data will become 0x00000303 and if the carry is present, it will
            be added with the last byte and it will become 0x00000304 which is not correct
            as per standard*/
            /* so check for previous four bytes and if it is equal to 0x00000303
            then subtract u4_strm_buf_offset by 1 */
            if(pu1_strm_buf[u4_strm_buf_offset - 1] == 0x03 &&
               pu1_strm_buf[u4_strm_buf_offset - 2] == 0x03 &&
               pu1_strm_buf[u4_strm_buf_offset - 3] == 0x00 &&
               pu1_strm_buf[u4_strm_buf_offset - 4] == 0x00)
            {
                u4_strm_buf_offset -= 1;
            }
            /* previous byte carry add will not result in overflow to        */
            /* u4_strm_buf_offset - 2 as we track 0xff as outstanding bytes  */
            pu1_strm_buf[u4_strm_buf_offset - 1] += carry;
            zero_run = 0;
        }

        /*        Insert outstanding bytes (if any)         */
        while(u4_out_standing_bytes)
        {
            UWORD8 u1_0_or_ff = carry ? 0 : 0xFF;

            PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, u1_0_or_ff, zero_run);

            u4_out_standing_bytes--;
        }

        /*  clear the carry in low */
        u4_low &= ((1 << (u4_bits_gen + CABAC_BITS)) - 1);

        /* extract the remaining bits;                                   */
        /* includes additional msb bit of low as per Figure 9-12      */
        bits_left = u4_bits_gen + 1;
        rem_bits = (u4_low >> (u4_bits_gen + CABAC_BITS - bits_left));

        if(bits_left >= 8)
        {
            last_byte = (rem_bits >> (bits_left - 8)) & 0xFF;
            PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, last_byte, zero_run);
            bits_left -= 8;
        }

        /* insert last byte along with rbsp stop bit(1) and 0's in the end */
        last_byte = (rem_bits << (8 - bits_left)) | (1 << (7 - bits_left));
        last_byte &= 0xFF;
        PUTBYTE_EPB(pu1_strm_buf, u4_strm_buf_offset, last_byte, zero_run);

        /* update the state variables and return success */
        ps_cabac->u4_strm_buf_offset = u4_strm_buf_offset;
        ps_cabac->i4_zero_bytes_run = 0;
        return (IHEVCE_SUCCESS);
    }
}

/**
******************************************************************************
*
*  @brief API to backup cabac ctxt at end of 2nd CTB row which is used to init
*   context at start of every row
*
*  @par   Description
*         API to backup cabac ctxt at end of 2nd CTB row which is used to init
*         context at start of every row
*
*  @param[inout]   ps_cabac
*  pointer to cabac context (handle)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_ctxt_backup(cab_ctxt_t *ps_cabac)
{
    memcpy(
        ps_cabac->au1_ctxt_models_top_right,
        ps_cabac->au1_ctxt_models,
        sizeof(ps_cabac->au1_ctxt_models));
    return (IHEVCE_SUCCESS);
}

/**
******************************************************************************
*
*  @brief Init cabac ctxt at every row start
*
*  @par   Description
*         API to init cabac ctxt at start of every row when entropy sync is
*         enabled
*
*  @param[inout]   ps_cabac
*  pointer to cabac context (handle)
*
*  @return      success or failure error code
*
******************************************************************************
*/
WORD32 ihevce_cabac_ctxt_row_init(cab_ctxt_t *ps_cabac)
{
    /* cabac engine initialization */
    ps_cabac->u4_low = 0;
    ps_cabac->u4_range = 510;
    ps_cabac->u4_bits_gen = 0;
    ps_cabac->u4_out_standing_bytes = 0;
    ps_cabac->i4_zero_bytes_run = 0;

    /*copy top right context as init context when starting to encode a row*/
    COPY_CABAC_STATES(
        ps_cabac->au1_ctxt_models, ps_cabac->au1_ctxt_models_top_right, IHEVC_CAB_CTXT_END);

    return (IHEVCE_SUCCESS);
}