/******************************************************************************
*
* Copyright (C) 2012 Ittiam Systems Pvt Ltd, Bangalore
*
* 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.
*
******************************************************************************/

/**
******************************************************************************
* @file ihevcd_cabac.h
*
* @brief
*  This file contains decoder cabac engine related structures and
*  interface prototypes
*
* @author
*  Ittiam
******************************************************************************
*/

#ifndef _IHEVCD_CABAC_H_
#define _IHEVCD_CABAC_H_

#include "ihevc_typedefs.h"
/*****************************************************************************/
/* Constant Macros                                                           */
/*****************************************************************************/
/**
*******************************************************************************
@brief
*******************************************************************************
 */
#define CABAC_BITS  9

/**
 * Following definitions control whether cabac functions are inlined as macros or
 * are called as functions. Set these to 0 to debug cabac leaf level functions
 * Note these macros assume FULLRANGE is 1.
 */
#define CABAC_DECODE_BIN            1
#define CABAC_DECODE_BYPASS_BIN     1
#define CABAC_DECODE_BYPASS_BINS    1

/*****************************************************************************/
/* Function Macros                                                           */
/*****************************************************************************/
#if CABAC_DECODE_BIN
#define IHEVCD_CABAC_DECODE_BIN(u4_bin, ps_cabac, ps_bitstrm, ctxt_index)       \
{                                                                               \
    UWORD32 u4_range = ps_cabac->u4_range;                                      \
    UWORD32 u4_ofst = ps_cabac->u4_ofst;                                        \
    UWORD32 u4_rlps;                                                            \
    UWORD8 *pu1_ctxt_model = &ps_cabac->au1_ctxt_models[ctxt_index];            \
    WORD32 state_mps = *pu1_ctxt_model;                                         \
    WORD32 clz;                                                                 \
    UWORD32 u4_qnt_range;                                                       \
                                                                                \
    /* Sanity checks */                                                         \
    ASSERT(FULLRANGE == 1);                                                     \
    ASSERT(u4_range >= 256);                                                    \
    ASSERT((ctxt_index >= 0) && (ctxt_index < IHEVC_CAB_CTXT_END));             \
    ASSERT(state_mps < 128);                                                    \
    clz = CLZ(u4_range);                                                        \
    clz -= (32 - RANGE_NUMBITS);                                                \
    u4_qnt_range = u4_range << clz;                                             \
    u4_qnt_range = (u4_qnt_range >> (RANGE_SHIFT + 6)) & 0x3;                   \
    /* Get the lps range from LUT based on quantized range and state */         \
    u4_rlps = gau1_ihevc_cabac_rlps[state_mps >> 1][u4_qnt_range];              \
    u4_rlps = u4_rlps << (RANGE_SHIFT - clz);                                   \
    u4_range -= u4_rlps;                                                        \
                                                                                \
    u4_bin = state_mps & 1;                                                     \
                                                                                \
    if(u4_ofst >= u4_range)                                                     \
    {                                                                           \
        u4_bin = 1 - u4_bin;                                                    \
        u4_ofst -= u4_range;                                                    \
        u4_range = u4_rlps;                                                     \
    }                                                                           \
                                                                                \
    *pu1_ctxt_model = gau1_ihevc_next_state[(state_mps << 1) | u4_bin];         \
                                                                                \
    /*****************************************************************/         \
    /* Re-normalization; calculate bits generated based on range(R)  */         \
    /*****************************************************************/         \
    if(u4_range < (1 << 8))                                                     \
    {                                                                           \
        UWORD32 u4_bits;                                                        \
        WORD32 numbits;                                                         \
        numbits = CLZ(u4_range);                                                \
        numbits -= (32 - RANGE_NUMBITS);                                        \
        BITS_GET(u4_bits, ps_bitstrm->pu4_buf, ps_bitstrm->u4_bit_ofst,         \
                 ps_bitstrm->u4_cur_word, ps_bitstrm->u4_nxt_word, numbits);    \
                                                                                \
        u4_ofst <<= numbits;                                                    \
        u4_ofst |= u4_bits;                                                     \
        u4_range <<= numbits;                                                   \
                                                                                \
    }                                                                           \
    /* Update the cabac context */                                              \
    ps_cabac->u4_range = u4_range;                                              \
    ps_cabac->u4_ofst = u4_ofst;                                                \
                                                                                \
}
#else
#define IHEVCD_CABAC_DECODE_BIN(u4_bin, ps_cabac, ps_bitstrm, ctxt_index)       \
        u4_bin = ihevcd_cabac_decode_bin(ps_cabac, ps_bitstrm, ctxt_index);
#endif

#if CABAC_DECODE_BYPASS_BIN
#define IHEVCD_CABAC_DECODE_BYPASS_BIN(u4_bin, ps_cabac, ps_bitstrm)            \
{                                                                               \
                                                                                \
    UWORD32 u4_range = ps_cabac->u4_range;                                      \
    UWORD32 u4_ofst = ps_cabac->u4_ofst;                                        \
    UWORD32 u4_bits;                                                            \
                                                                                \
    /* Sanity checks */                                                         \
    ASSERT(FULLRANGE == 1);                                                     \
    ASSERT(u4_range >= 256);                                                    \
                                                                                \
    BIT_GET(u4_bits, ps_bitstrm->pu4_buf, ps_bitstrm->u4_bit_ofst,              \
            ps_bitstrm->u4_cur_word, ps_bitstrm->u4_nxt_word);                  \
                                                                                \
    u4_ofst <<= 1;                                                              \
    u4_ofst |= u4_bits;                                                         \
                                                                                \
    u4_bin = 0;                                                                 \
    if(u4_ofst >= u4_range)                                                     \
    {                                                                           \
        u4_bin = 1;                                                             \
        u4_ofst -= u4_range;                                                    \
    }                                                                           \
                                                                                \
    /* Update the cabac context */                                              \
    ps_cabac->u4_ofst = u4_ofst;                                                \
}
#else

#define IHEVCD_CABAC_DECODE_BYPASS_BIN(u4_bin, ps_cabac, ps_bitstrm)            \
                u4_bin = ihevcd_cabac_decode_bypass_bin(ps_cabac, ps_bitstrm);
#endif

#if CABAC_DECODE_BYPASS_BINS
#define IHEVCD_CABAC_DECODE_BYPASS_BINS(u4_bins, ps_cabac, ps_bitstrm, numbins) \
{                                                                               \
    UWORD32 u4_range = ps_cabac->u4_range;                                      \
    UWORD32 u4_ofst = ps_cabac->u4_ofst;                                        \
    UWORD32 u4_bits;                                                            \
    ASSERT(FULLRANGE == 1);                                                     \
    ASSERT(u4_range >= 256);                                                    \
    ASSERT(numbins > 0);                                                        \
    {                                                                           \
        WORD32 numbins_tmp = numbins;                                           \
        /* Sanity checks */                                                     \
        ASSERT(numbins < 17);                                                   \
                                                                                \
        u4_bins = 0;                                                            \
                                                                                \
        BITS_GET(u4_bits, ps_bitstrm->pu4_buf, ps_bitstrm->u4_bit_ofst,         \
                    ps_bitstrm->u4_cur_word, ps_bitstrm->u4_nxt_word, numbins); \
        do                                                                      \
        {                                                                       \
            UWORD32 u4_bit;                                                     \
            numbins_tmp--;                                                      \
            u4_bit = (u4_bits >> numbins_tmp) & 1;                              \
            u4_ofst <<= 1;                                                      \
            u4_ofst |= u4_bit;                                                  \
                                                                                \
            u4_bins <<= 1;                                                      \
            if(u4_ofst >= u4_range)                                             \
            {                                                                   \
                u4_bins += 1;                                                   \
                u4_ofst -= u4_range;                                            \
            }                                                                   \
        }while(numbins_tmp);                                                    \
                                                                                \
        /* Update the cabac context */                                          \
        ps_cabac->u4_ofst = u4_ofst;                                            \
    }                                                                           \
}


#else

#define IHEVCD_CABAC_DECODE_BYPASS_BINS(u4_bins, ps_cabac, ps_bitstrm, numbins) \
      u4_bins = ihevcd_cabac_decode_bypass_bins(ps_cabac, ps_bitstrm, numbins);

#endif
/*****************************************************************************/
/* Structures                                                                */
/*****************************************************************************/



/*****************************************************************************/
/* Extern Function Declarations                                              */
/*****************************************************************************/
IHEVCD_ERROR_T    ihevcd_cabac_init
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t   *ps_bitstrm,
                WORD32      slice_qp,
                WORD32      cabac_init_idc,
                const UWORD8      *pu1_init_ctxt
);



UWORD32    ihevcd_cabac_decode_bin
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32      ctxt_index
);

UWORD32    ihevcd_cabac_decode_bypass_bin
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm
);

UWORD32    ihevcd_cabac_decode_terminate
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm
);

UWORD32    ihevcd_cabac_decode_bypass_bins
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32       num_bins
);

UWORD32    ihevcd_cabac_decode_bins_tunary
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32       c_max,
                WORD32       ctxt_index,
                WORD32       ctxt_shift,
                WORD32       ctxt_inc_max

);

UWORD32    ihevcd_cabac_decode_bypass_bins_tunary
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32       c_max

);

UWORD32    ihevcd_cabac_decode_bypass_bins_egk
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32       k
);

UWORD32    ihevcd_cabac_decode_bypass_bins_trunc_rice
(
                cab_ctxt_t  *ps_cabac,
                bitstrm_t *ps_bitstrm,
                WORD32       c_rice_param,
                WORD32       c_rice_max
);

IHEVCD_ERROR_T  ihevcd_cabac_flush(cab_ctxt_t  *ps_cabac);

IHEVCD_ERROR_T ihevcd_cabac_reset(cab_ctxt_t *ps_cabac,
                                  bitstrm_t *ps_bitstrm);

#endif /* _IHEVCD_CABAC_H_ */