/******************************************************************************
 *
 * Copyright (C) 2015 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
*  ih264e_cabac_encode.c
*
* @brief
*  Contains all functions to encode in CABAC entropy mode
*
* @author
*  ittiam
*
* @par List of Functions
*  - ih264e_cabac_enc_mb_skip
*  - ih264e_cabac_enc_intra_mb_type
*  - ih264e_cabac_enc_4x4mb_modes
*  - ih264e_cabac_enc_chroma_predmode
*  - ih264e_cabac_enc_cbp
*  - ih264e_cabac_enc_mb_qp_delta
*  - ih264e_cabac_write_coeff4x4
*  - ih264e_cabac_encode_residue_luma_dc
*  - ih264e_cabac_write_chroma_residue
*  - ih264e_cabac_encode_residue
*  - ih264e_cabac_enc_ctx_mvd
*  - ih264e_cabac_enc_mvds_p16x16
*  - ih264e_cabac_enc_mvds_b16x16
*  - ih264e_write_islice_mb_cabac
*  - ih264e_write_pslice_mb_cabac
*  - ih264e_write_bslice_mb_cabac
*
* @remarks
*  none
*
*******************************************************************************
*/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/

/* System Include Files */
#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <string.h>

/* User Include Files */
#include "ih264e_config.h"
#include "ih264_typedefs.h"
#include "iv2.h"
#include "ive2.h"

#include "ih264_debug.h"
#include "ih264_macros.h"
#include "ih264_error.h"
#include "ih264_defs.h"
#include "ih264_mem_fns.h"
#include "ih264_padding.h"
#include "ih264_structs.h"
#include "ih264_trans_quant_itrans_iquant.h"
#include "ih264_inter_pred_filters.h"
#include "ih264_intra_pred_filters.h"
#include "ih264_deblk_edge_filters.h"
#include "ih264_cavlc_tables.h"
#include "ih264_cabac_tables.h"
#include "ih264_platform_macros.h"

#include "ime_defs.h"
#include "ime_distortion_metrics.h"
#include "ime_structs.h"

#include "irc_cntrl_param.h"
#include "irc_frame_info_collector.h"

#include "ih264e_error.h"
#include "ih264e_defs.h"
#include "ih264e_bitstream.h"
#include "ih264e_cabac_structs.h"
#include "ih264e_structs.h"
#include "ih264e_encode_header.h"
#include "ih264e_cabac.h"
#include "ih264e_statistics.h"
#include "ih264e_trace.h"

/*****************************************************************************/
/* Global Definitions                                                        */
/*****************************************************************************/

/* ! < Table 9-36 : Binarization for macroblock types in I slices in ITU_T_H264
 * Bits 0-7 : binarised value
 * Bits 8-15: length of binary sequence
 */
static const UWORD32 u4_mb_type_intra[26] =
    { 0x0100, 0x0620, 0x0621, 0x0622, 0x0623, 0x0748, 0x0749, 0x074a, 0x074b,
      0x074c, 0x074d, 0x074e, 0x074f, 0x0628, 0x0629, 0x062a, 0x062b, 0x0758,
      0x0759, 0x075a, 0x075b, 0x075c, 0x075d, 0x075e, 0x075f, 0x0203 };

/* CtxInc for mb types */
static const UWORD32 u4_mb_ctxinc[2][26] =
{
    /* Intra CtxInc's */
    {   0x00,
        0x03467, 0x03467, 0x03467, 0x03467, 0x034567, 0x034567, 0x034567,
        0x034567, 0x034567, 0x034567, 0x034567, 0x034567, 0x03467, 0x03467,
        0x03467, 0x03467, 0x034567, 0x034567, 0x034567, 0x034567, 0x034567,
        0x034567, 0x034567, 0x034567, 0x00},
    /* Inter CtxInc's */
    {   0x00,
        0x001233, 0x001233, 0x001233, 0x001233, 0x0012233, 0x0012233, 0x0012233,
        0x0012233, 0x0012233, 0x0012233, 0x0012233, 0x0012233, 0x001233, 0x001233,
        0x001233, 0x001233, 0x0012233, 0x0012233, 0x0012233, 0x0012233, 0x0012233,
        0x0012233, 0x0012233, 0x0012233, 0x00}
};

/* ! < Table 9-37 : Binarization for macroblock types in B slices  in ITU_T_H264-201402
 * Bits 0-7 : binarised value
 * Bits 8-15: length of binary sequence */
static const UWORD32 u4_b_mb_type[27] =
    { 0x0100, 0x0301, 0x0305, 0x0603, 0x0623, 0x0613, 0x0633, 0x060b, 0x062b,
      0x061b, 0x063b, 0x061f, 0x0707, 0x0747, 0x0727, 0x0767, 0x0717, 0x0757,
      0x0737, 0x0777, 0x070f, 0x074f, 0x063f };

/* CtxInc for mb types in B slices */
static const UWORD32 ui_b_mb_type_ctx_inc[27] =
    { 0x00, 0x0530, 0x0530, 0x0555430, 0x0555430, 0x0555430, 0x0555430,
      0x0555430, 0x0555430, 0x0555430, 0x0555430, 0x0555430, 0x05555430,
      0x05555430, 0x05555430, 0x05555430, 0x05555430, 0x05555430, 0x05555430,
      0x05555430, 0x05555430, 0x05555430, 0x0555430 };


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

/**
*******************************************************************************
*
* @brief
*  Encodes mb_skip_flag using CABAC entropy coding mode.
*
* @param[in] u1_mb_skip_flag
*  mb_skip_flag
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @param[in] u4_ctxidx_offset
*  ctxIdxOffset for mb_skip_flag context
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_mb_skip(UWORD8 u1_mb_skip_flag,
                                     cabac_ctxt_t *ps_cabac_ctxt,
                                     UWORD32 u4_ctxidx_offset)
{
    UWORD8 u4_ctx_inc;
    WORD8 a, b;

    a = ((ps_cabac_ctxt->ps_left_ctxt_mb_info->u1_mb_type & CAB_SKIP_MASK) ?
                    0 : 1);
    b = ((ps_cabac_ctxt->ps_top_ctxt_mb_info->u1_mb_type & CAB_SKIP_MASK) ?
                    0 : 1);

    u4_ctx_inc = a + b;

    /* Encode the bin */
    ih264e_cabac_encode_bin(ps_cabac_ctxt,
                            (UWORD32) u1_mb_skip_flag,
                            ps_cabac_ctxt->au1_cabac_ctxt_table +
                                    u4_ctxidx_offset + u4_ctx_inc);
}

/**
*******************************************************************************
*
* @brief
*  Encodes mb_type for an intra MB.
*
* @param[in] u4_slice_type
*  slice type
*
* @param[in] u4_intra_mb_type
*  MB type (Table 7-11)
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @param[in] u4_ctxidx_offset
*  ctxIdxOffset for mb_type context
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_intra_mb_type(UWORD32 u4_slice_type,
                                           UWORD32 u4_intra_mb_type,
                                           cabac_ctxt_t *ps_cabac_ctxt,
                                           UWORD32 u4_ctx_idx_offset)
{
    encoding_envirnoment_t *ps_cab_enc_env = &(ps_cabac_ctxt->s_cab_enc_env);
    bin_ctxt_model *pu1_mb_bin_ctxt, *pu1_bin_ctxt;
    UWORD8 u1_bin;
    mb_info_ctxt_t *ps_left_ctxt = ps_cabac_ctxt->ps_left_ctxt_mb_info;
    mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    UWORD32 u4_bins;
    UWORD32 u4_ctx_inc;
    WORD8 i1_bins_len;
    UWORD32 u4_code_int_range;
    UWORD32 u4_code_int_low;
    UWORD16 u2_quant_code_int_range;
    UWORD16 u4_code_int_range_lps;
    WORD8 i;
    UWORD8 u1_ctx_inc;
    UWORD32 u4_table_val;

    pu1_mb_bin_ctxt = ps_cabac_ctxt->au1_cabac_ctxt_table + u4_ctx_idx_offset;

    u4_bins = u4_mb_type_intra[u4_intra_mb_type];
    i1_bins_len = (WORD8) ((u4_bins >> 8) & 0x0f);
    u4_ctx_inc = u4_mb_ctxinc[(u4_slice_type != ISLICE)][u4_intra_mb_type];
    u1_ctx_inc = 0;
    if (u4_slice_type == ISLICE)
    {
        if (ps_left_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
            u1_ctx_inc += ((ps_left_ctxt->u1_mb_type != CAB_I4x4) ? 1 : 0);
        if (ps_top_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
            u1_ctx_inc += ((ps_top_ctxt->u1_mb_type != CAB_I4x4) ? 1 : 0);

        u4_ctx_inc = (u4_ctx_inc | (u1_ctx_inc << ((i1_bins_len - 1) << 2)));
    }
    else
    {
        pu1_mb_bin_ctxt += 3;
        if (u4_slice_type == BSLICE)
            pu1_mb_bin_ctxt += 2;

    }

    u4_code_int_range = ps_cab_enc_env->u4_code_int_range;
    u4_code_int_low = ps_cab_enc_env->u4_code_int_low;

    for (i = (i1_bins_len - 1); i >= 0; i--)
    {
        WORD32 shift;

        u1_ctx_inc = ((u4_ctx_inc >> (i << 2)) & 0x0f);
        u1_bin = ((u4_bins >> i) & 0x01);
        /* Encode the bin */
        pu1_bin_ctxt = pu1_mb_bin_ctxt + u1_ctx_inc;
        if (i != (i1_bins_len - 2))
        {
            WORD8 i1_mps = !!((*pu1_bin_ctxt) & (0x40));
            WORD8 i1_state = (*pu1_bin_ctxt) & 0x3F;

            u2_quant_code_int_range = ((u4_code_int_range >> 6) & 0x03);
            u4_table_val = gau4_ih264_cabac_table[i1_state][u2_quant_code_int_range];
            u4_code_int_range_lps = u4_table_val & 0xFF;

            u4_code_int_range -= u4_code_int_range_lps;
            if (u1_bin != i1_mps)
            {
                u4_code_int_low += u4_code_int_range;
                u4_code_int_range = u4_code_int_range_lps;
                if (i1_state == 0)
                {
                    /* MPS(CtxIdx) = 1 - MPS(CtxIdx) */
                    i1_mps = 1 - i1_mps;
                }

                i1_state = (u4_table_val >> 15) & 0x3F;
            }
            else
            {
                i1_state = (u4_table_val >> 8) & 0x3F;

            }

            (*pu1_bin_ctxt) = (i1_mps << 6) | i1_state;
        }
        else
        {
            u4_code_int_range -= 2;
        }

        /* Renormalize */
        /*****************************************************************/
        /* Renormalization; calculate bits generated based on range(R)   */
        /* Note : 6 <= R < 512; R is 2 only for terminating encode       */
        /*****************************************************************/
        GETRANGE(shift, u4_code_int_range);
        shift = 9 - shift;
        u4_code_int_low <<= shift;
        u4_code_int_range <<= shift;

        /* bits to be inserted in the bitstream */
        ps_cab_enc_env->u4_bits_gen += shift;
        ps_cab_enc_env->u4_code_int_range = u4_code_int_range;
        ps_cab_enc_env->u4_code_int_low = u4_code_int_low;

        /* generate stream when a byte is ready */
        if (ps_cab_enc_env->u4_bits_gen > CABAC_BITS)
        {
            ih264e_cabac_put_byte(ps_cabac_ctxt);
            u4_code_int_range = ps_cab_enc_env->u4_code_int_range;
            u4_code_int_low = ps_cab_enc_env->u4_code_int_low;
        }
    }
}

/**
*******************************************************************************
*
* @brief
*  Encodes prev_intra4x4_pred_mode_flag and rem_intra4x4_pred_mode using
*  CABAC entropy coding mode
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @param[in] pu1_intra_4x4_modes
*  Pointer to array containing prev_intra4x4_pred_mode_flag and
*  rem_intra4x4_pred_mode
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_4x4mb_modes(cabac_ctxt_t *ps_cabac_ctxt,
                                         UWORD8 *pu1_intra_4x4_modes)
{
    WORD32 i;
    WORD8 byte;

    for (i = 0; i < 16; i += 2)
    {
        /* sub blk idx 1 */
        byte = pu1_intra_4x4_modes[i >> 1];
        if (byte & 0x1)
        {
            ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                    1,
                                    ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + PREV_INTRA4X4_PRED_MODE_FLAG);
        }
        else
        {
            /* Binarization is FL and Cmax=7 */
            ih264e_encode_decision_bins(byte & 0xF,
                                        4,
                                        0x05554,
                                        4,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + REM_INTRA4X4_PRED_MODE - 5,
                                        ps_cabac_ctxt);
        }
        /* sub blk idx 2 */
        byte >>= 4;
        if (byte & 0x1)
        {
            ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                    1,
                                    ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + PREV_INTRA4X4_PRED_MODE_FLAG);
        }
        else
        {
            ih264e_encode_decision_bins(byte & 0xF,
                                        4,
                                        0x05554,
                                        4,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + REM_INTRA4X4_PRED_MODE - 5,
                                        ps_cabac_ctxt);
        }
    }
}

/**
*******************************************************************************
*
* @brief
*  Encodes chroma intra pred mode for the MB.
*
* @param[in] u1_chroma_pred_mode
*  Chroma intra prediction mode
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_chroma_predmode(UWORD8 u1_chroma_pred_mode,
                                             cabac_ctxt_t *ps_cabac_ctxt)
{
    WORD8 i1_temp;
    mb_info_ctxt_t *ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;
    mb_info_ctxt_t *ps_left_ctxt = ps_cabac_ctxt->ps_left_ctxt_mb_info;
    mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    UWORD32 u4_bins = 0;
    WORD8 i1_bins_len = 1;
    UWORD32 u4_ctx_inc = 0;
    UWORD8 a, b;

    a = ((ps_left_ctxt->u1_intrapred_chroma_mode != 0) ? 1 : 0);
    b = ((ps_top_ctxt->u1_intrapred_chroma_mode != 0) ? 1 : 0);

    /* Binarization is TU and Cmax=3 */
    ps_curr_ctxt->u1_intrapred_chroma_mode = u1_chroma_pred_mode;

    u4_ctx_inc = a + b;
    u4_ctx_inc = (u4_ctx_inc | 0x330);
    if (u1_chroma_pred_mode)
    {
        u4_bins = 1;
        i1_temp = u1_chroma_pred_mode;
        i1_temp--;
        /* Put a stream of 1's of length Chromaps_pred_mode_ctxt value */
        while (i1_temp)
        {
            u4_bins = (u4_bins | (1 << i1_bins_len));
            i1_bins_len++;
            i1_temp--;
        }
        /* If Chromaps_pred_mode_ctxt < Cmax i.e 3. Terminate put a zero */
        if (u1_chroma_pred_mode < 3)
        {
            i1_bins_len++;
        }
    }

    ih264e_encode_decision_bins(u4_bins,
                                i1_bins_len,
                                u4_ctx_inc,
                                3,
                                ps_cabac_ctxt->au1_cabac_ctxt_table
                                    + INTRA_CHROMA_PRED_MODE,
                                ps_cabac_ctxt);
}

/**
*******************************************************************************
*
* @brief Encodes CBP for the MB.
*
* @param[in] u1_cbp
*  CBP for the MB
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_cbp(UWORD32 u4_cbp, cabac_ctxt_t *ps_cabac_ctxt)
{
    mb_info_ctxt_t *ps_left_ctxt = ps_cabac_ctxt->ps_left_ctxt_mb_info;
    mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    WORD8 i2_cbp_chroma, i, j;
    UWORD8 u1_ctxt_inc, u1_bin;
    UWORD8 a, b;
    UWORD32 u4_ctx_inc;
    UWORD32 u4_bins;
    WORD8 i1_bins_len;

    /* CBP Luma, FL, Cmax = 15, L = 4 */
    u4_ctx_inc = 0;
    u4_bins = 0;
    i1_bins_len = 5;
    for (i = 0; i < 4; i++)
    {
        /* calulate ctxtInc, depending on neighbour availability */
        /* u1_ctxt_inc = CondTerm(A) + 2 * CondTerm(B);
         A: Left block and B: Top block */

        /* Check for Top availability */
        if (i >> 1)
        {
            j = i - 2;
            /* Top is available always and it's current MB */
            b = (((u4_cbp >> j) & 0x01) != 0 ? 0 : 1);
        }
        else
        {
            /* for blocks whose top reference is in another MB */
            {
                j = i + 2;
                b = ((ps_top_ctxt->u1_cbp >> j) & 0x01) ? 0 : 1;
            }
        }

        /* Check for Left availability */
        if (i & 0x01)
        {
            /* Left is available always and it's current MB */
            j = i - 1;
            a = (((u4_cbp >> j) & 0x01) != 0 ? 0 : 1);
        }
        else
        {
            {
                j = i + 1;
                a = ((ps_left_ctxt->u1_cbp >> j) & 0x01) ? 0 : 1;
            }
        }
        u1_ctxt_inc = a + 2 * b;
        u1_bin = ((u4_cbp >> i) & 0x01);
        u4_ctx_inc = (u4_ctx_inc | (u1_ctxt_inc << (i << 2)));
        u4_bins = (u4_bins | (u1_bin << i));
    }

    /* CBP Chroma, TU, Cmax = 2 */
    i2_cbp_chroma = u4_cbp >> 4;
    /* calulate ctxtInc, depending on neighbour availability */
    a = (ps_left_ctxt->u1_cbp > 15) ? 1 : 0;
    b = (ps_top_ctxt->u1_cbp > 15) ? 1 : 0;

    u1_ctxt_inc = a + 2 * b;
    if (i2_cbp_chroma)
    {
        u4_ctx_inc = u4_ctx_inc | ((4 + u1_ctxt_inc) << 16);
        u4_bins = (u4_bins | 0x10);
        /* calulate ctxtInc, depending on neighbour availability */
        a = (ps_left_ctxt->u1_cbp > 31) ? 1 : 0;
        b = (ps_top_ctxt->u1_cbp > 31) ? 1 : 0;
        u1_ctxt_inc = a + 2 * b;
        u4_ctx_inc = u4_ctx_inc | ((8 + u1_ctxt_inc) << 20);
        u4_bins = (u4_bins | (((i2_cbp_chroma >> 1) & 0x01) << i1_bins_len));
        i1_bins_len++;
    }
    else
    {
        u4_ctx_inc = (u4_ctx_inc | ((4 + u1_ctxt_inc) << 16));
    }
    ih264e_encode_decision_bins(u4_bins, i1_bins_len, u4_ctx_inc, 8,
                                ps_cabac_ctxt->au1_cabac_ctxt_table + CBP_LUMA,
                                ps_cabac_ctxt);
}

/**
*******************************************************************************
*
* @brief Encodes mb_qp_delta for the MB.
*
* @param[in] i1_mb_qp_delta
*  mb_qp_delta
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_mb_qp_delta(WORD8 i1_mb_qp_delta,
                                         cabac_ctxt_t *ps_cabac_ctxt)
{
    UWORD8 u1_code_num;
    UWORD8 u1_ctxt_inc;
    UWORD32 u4_ctx_inc;
    UWORD32 u4_bins;
    WORD8 i1_bins_len;
    UWORD8 u1_ctx_inc, u1_bin;

    /* Range of ps_mb_qp_delta_ctxt= -26 to +25 inclusive */
    ASSERT((i1_mb_qp_delta < 26) && (i1_mb_qp_delta > -27));

    /* if ps_mb_qp_delta_ctxt=0, then codeNum=0 */
    u1_code_num = 0;
    if (i1_mb_qp_delta > 0)
        u1_code_num = (i1_mb_qp_delta << 1) - 1;
    else if (i1_mb_qp_delta < 0)
        u1_code_num = (ABS(i1_mb_qp_delta)) << 1;

    u4_ctx_inc = 0;
    u4_bins = 0;
    i1_bins_len = 1;
    /* calculate ctxtInc, depending on neighbour availability */
    u1_ctxt_inc = (!(!(ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt)));
    ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = i1_mb_qp_delta;

    if (u1_code_num == 0)
    {
        /* b0 */
        u1_bin = (UWORD8) (u4_bins);
        u1_ctx_inc = u1_ctxt_inc & 0x0f;
        /* Encode the bin */
        ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                u1_bin,
                                ps_cabac_ctxt->au1_cabac_ctxt_table + MB_QP_DELTA
                                        + u1_ctx_inc);

    }
    else
    {
        /* b0 */
        u4_ctx_inc = u1_ctxt_inc;
        u4_bins = 1;
        u1_code_num--;
        if (u1_code_num == 0)
        {
            /* b1 */
            u4_ctx_inc = (u4_ctx_inc | 0x20);
            i1_bins_len++;
            ih264e_encode_decision_bins(u4_bins, i1_bins_len, u4_ctx_inc, 3,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table + MB_QP_DELTA,
                                        ps_cabac_ctxt);
        }
        else
        {
            /* b1 */
            u4_ctx_inc = (u4_ctx_inc | 0x20);
            u4_bins = (u4_bins | (1 << i1_bins_len));
            i1_bins_len++;
            u1_code_num--;
            /* BinIdx from b2 onwards */
            if (u1_code_num < 30)
            { /* maximum i1_bins_len = 31 */
                while (u1_code_num)
                {
                    u4_bins = (u4_bins | (1 << i1_bins_len));
                    i1_bins_len++;
                    u1_code_num--;
                };
                u4_ctx_inc = (u4_ctx_inc | 0x300);
                i1_bins_len++;
                ih264e_encode_decision_bins(u4_bins,
                                            i1_bins_len,
                                            u4_ctx_inc,
                                            2,
                                            ps_cabac_ctxt->au1_cabac_ctxt_table
                                                + MB_QP_DELTA,
                                            ps_cabac_ctxt);
            }
            else
            {
                /* maximum i1_bins_len = 53 */
                u4_bins = 0xffffffff;
                i1_bins_len = 32;
                u4_ctx_inc = (u4_ctx_inc | 0x300);
                u1_code_num -= 30;
                ih264e_encode_decision_bins(u4_bins,
                                            i1_bins_len,
                                            u4_ctx_inc,
                                            2,
                                            ps_cabac_ctxt->au1_cabac_ctxt_table
                                                + MB_QP_DELTA,
                                            ps_cabac_ctxt);
                u4_bins = 0;
                i1_bins_len = 0;
                u4_ctx_inc = 0x033;
                while (u1_code_num)
                {
                    u4_bins = (u4_bins | (1 << i1_bins_len));
                    i1_bins_len++;
                    u1_code_num--;
                };

                u4_ctx_inc = (u4_ctx_inc | 0x300);
                i1_bins_len++;
                ih264e_encode_decision_bins(u4_bins,
                                            i1_bins_len,
                                            u4_ctx_inc,
                                            1,
                                            ps_cabac_ctxt->au1_cabac_ctxt_table
                                                + MB_QP_DELTA,
                                            ps_cabac_ctxt);
            }
        }
    }
}

/**
*******************************************************************************
* @brief
*  Encodes 4x4 residual_block_cabac as defined in 7.3.5.3.3.
*
* @param[in] pi2_res_block
*  pointer to the array of residues
*
* @param[in]  u1_nnz
*  Number of non zero coeffs in the block
*
* @param[in] u1_max_num_coeffs
*  Max number of coeffs that can be there in the block
*
* @param[in] u2_sig_coeff_map
*  Significant coeff map
*
* @param[in] u4_ctx_cat_offset
*  ctxIdxOffset for  absolute value contexts
*
* @param[in]  pu1_ctxt_sig_coeff
*  Pointer to residual state variables
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_write_coeff4x4(WORD16 *pi2_res_block, UWORD8 u1_nnz,
                                        UWORD8 u1_max_num_coeffs,
                                        UWORD16 u2_sig_coeff_map,
                                        UWORD32 u4_ctx_cat_offset,
                                        bin_ctxt_model *pu1_ctxt_sig_coeff,
                                        cabac_ctxt_t *ps_cabac_ctxt)
{
    WORD8 i;
    WORD16 *pi16_coeffs;
    UWORD32 u4_sig_coeff, u4_bins;
    UWORD32 u4_ctx_inc;
    UWORD8 u1_last_sig_coef_index = (31 - CLZ(u2_sig_coeff_map));

    /* Always put Coded Block Flag as 1 */
    pi16_coeffs = pi2_res_block;
    {
        bin_ctxt_model *pu1_bin_ctxt;
        UWORD8 u1_bin, uc_last;

        i = 0;
        pu1_bin_ctxt = pu1_ctxt_sig_coeff;
        u4_sig_coeff = 0;
        u1_bin = 1;
        if ((u1_last_sig_coef_index))
        {
            u1_bin = !!(u2_sig_coeff_map & 01);
        }
        uc_last = 1;

        do
        {
            /* Encode Decision */
            ih264e_cabac_encode_bin(ps_cabac_ctxt, u1_bin, pu1_bin_ctxt);

            if (u1_bin & uc_last)
            {
                u4_sig_coeff = (u4_sig_coeff | (1 << i));
                pu1_bin_ctxt = pu1_ctxt_sig_coeff + i
                                + LAST_SIGNIFICANT_COEFF_FLAG_FRAME
                                - SIGNIFICANT_COEFF_FLAG_FRAME;
                u1_bin = (i == u1_last_sig_coef_index);
                uc_last = 0;
            }
            else
            {
                i = i + 1;
                pu1_bin_ctxt = pu1_ctxt_sig_coeff + i;
                u1_bin = (i == u1_last_sig_coef_index);
                uc_last = 1;
                if ((i != u1_last_sig_coef_index))
                {
                    u1_bin = !!((u2_sig_coeff_map >> i) & 01);
                }
            }
        } while (!((i > u1_last_sig_coef_index) || (i > (u1_max_num_coeffs - 1))));
    }

    /* Encode coeff_abs_level_minus1 and coeff_sign_flag */
    {
        UWORD8 u1_sign;
        UWORD16 u2_abs_level;
        UWORD8 u1_abs_level_equal1 = 1, u1_abs_level_gt1 = 0;
        UWORD8 u1_ctx_inc;
        UWORD8 u1_coff;
        WORD16 i2_sufs;
        WORD8 i1_bins_len;

        i = u1_last_sig_coef_index;
        pi16_coeffs = pi2_res_block + u1_nnz - 1;
        do
        {
            {
                u4_sig_coeff = u4_sig_coeff & ((1 << i) - 1);
                u4_bins = 0;
                u4_ctx_inc = 0;
                i1_bins_len = 1;
                /* Encode the AbsLevelMinus1 */
                u2_abs_level = ABS(*(pi16_coeffs)) - 1;
                /* CtxInc for bin0 */
                u4_ctx_inc = MIN(u1_abs_level_equal1, 4);
                /* CtxInc for remaining */
                u1_ctx_inc = 5 + MIN(u1_abs_level_gt1, 4);
                u4_ctx_inc = u4_ctx_inc + (u1_ctx_inc << 4);
                if (u2_abs_level)
                {
                    u1_abs_level_gt1++;
                    u1_abs_level_equal1 = 0;
                }
                if (!u1_abs_level_gt1)
                    u1_abs_level_equal1++;

                u1_coff = 14;
                if (u2_abs_level >= u1_coff)
                {
                    /* Prefix TU i.e string of 14 1's */
                    u4_bins = 0x3fff;
                    i1_bins_len = 14;
                    ih264e_encode_decision_bins(
                                    u4_bins,
                                    i1_bins_len,
                                    u4_ctx_inc,
                                    1,
                                    ps_cabac_ctxt->au1_cabac_ctxt_table
                                                    + u4_ctx_cat_offset,
                                    ps_cabac_ctxt);

                    /* Suffix, uses EncodeBypass */
                    i2_sufs = u2_abs_level - u1_coff;

                    u4_bins = ih264e_cabac_UEGk0_binarization(i2_sufs,
                                                              &i1_bins_len);

                    ih264e_cabac_encode_bypass_bins(ps_cabac_ctxt, u4_bins,
                                                    i1_bins_len);
                }
                else
                {
                    /* Prefix only */
                    u4_bins = (1 << u2_abs_level) - 1;
                    i1_bins_len = u2_abs_level + 1;
                    /* Encode Terminating bit */
                    ih264e_encode_decision_bins(
                                    u4_bins,
                                    i1_bins_len,
                                    u4_ctx_inc,
                                    1,
                                    ps_cabac_ctxt->au1_cabac_ctxt_table
                                                    + u4_ctx_cat_offset,
                                    ps_cabac_ctxt);
                }
            }
            /* encode coeff_sign_flag[i] */
            u1_sign = ((*pi16_coeffs) < 0) ? 1 : 0;
            ih264e_cabac_encode_bypass_bin(ps_cabac_ctxt, u1_sign);
            i = CLZ(u4_sig_coeff);
            i = 31 - i;
            pi16_coeffs--;
        } while (u4_sig_coeff);
    }
}

/**
*******************************************************************************
* @brief
*  Write DC coeffs for intra predicted luma block
*
* @param[in] ps_ent_ctxt
*  Pointer to entropy context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_encode_residue_luma_dc(entropy_ctxt_t *ps_ent_ctxt)
{
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    tu_sblk_coeff_data_t *ps_mb_coeff_data;
    void *pv_mb_coeff_data = ps_ent_ctxt->pv_mb_coeff_data;
    UWORD16 u2_sig_coeff_map;
    WORD16 *pi2_res_block;
    UWORD8 u1_nnz;
    UWORD8 u1_cbf;
    mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    mb_info_ctxt_t *p_CurCtxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;

    PARSE_COEFF_DATA_BLOCK_4x4(pv_mb_coeff_data, ps_mb_coeff_data, u1_nnz,
                               u2_sig_coeff_map, pi2_res_block);

    u1_cbf = !!(u1_nnz);

    {
        UWORD32 u4_ctx_inc;
        UWORD8 u1_a, u1_b;

        u1_a = ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] & 0x1;
        u1_b = ps_top_ctxt->u1_yuv_dc_csbp & 0x1;
        u4_ctx_inc = u1_a + (u1_b << 1);

        ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                u1_cbf,
                                ps_cabac_ctxt->au1_cabac_ctxt_table + CBF
                                        + (LUMA_DC_CTXCAT << 2) + u4_ctx_inc);
    }

    /* Write coded_block_flag */
    if (u1_cbf)
    {
        ih264e_cabac_write_coeff4x4(pi2_res_block,
                                   u1_nnz,
                                   15,
                                   u2_sig_coeff_map,
                                   COEFF_ABS_LEVEL_MINUS1 + COEFF_ABS_LEVEL_CAT_0_OFFSET,
                                   ps_cabac_ctxt->au1_cabac_ctxt_table
                                        + SIGNIFICANT_COEFF_FLAG_FRAME
                                        + SIG_COEFF_CTXT_CAT_0_OFFSET,
                                   ps_cabac_ctxt);

        ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] |= 0x1;
        p_CurCtxt->u1_yuv_dc_csbp |= 0x1;
    }
    else
    {
        ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
        p_CurCtxt->u1_yuv_dc_csbp &= 0x6;
    }

    ps_ent_ctxt->pv_mb_coeff_data = pv_mb_coeff_data;
}

/**
*******************************************************************************
* @brief
*  Write chroma residues to the bitstream
*
* @param[in] ps_ent_ctxt
*  Pointer to entropy context structure
*
* @param[in] u1_chroma_cbp
*  coded block pattern, chroma
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_write_chroma_residue(entropy_ctxt_t *ps_ent_ctxt,
                                              UWORD8 u1_chroma_cbp)
{
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    tu_sblk_coeff_data_t *ps_mb_coeff_data;
    void *pv_mb_coeff_data = ps_ent_ctxt->pv_mb_coeff_data;
    UWORD16 u2_sig_coeff_map;
    UWORD8 u1_nnz;
    mb_info_ctxt_t *ps_top_ctxt_mb_info, *ps_curr_ctxt;

    ps_top_ctxt_mb_info = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;

    /********************/
    /* Write Chroma DC */
    /********************/
    {
        WORD16 *pi2_res_block;
        UWORD8 u1_left_dc_csbp, u1_top_dc_csbp, u1_uv, u1_cbf;

        u1_left_dc_csbp = (ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0]) >> 1;
        u1_top_dc_csbp = (ps_top_ctxt_mb_info->u1_yuv_dc_csbp) >> 1;

        for (u1_uv = 0; u1_uv < 2; u1_uv++)
        {
            PARSE_COEFF_DATA_BLOCK_4x4(pv_mb_coeff_data, ps_mb_coeff_data,
                                       u1_nnz, u2_sig_coeff_map, pi2_res_block);
            u1_cbf = !!(u1_nnz);
            {
                UWORD8 u1_a, u1_b;
                UWORD32 u4_ctx_inc;
                u1_a = (u1_left_dc_csbp >> u1_uv) & 0x01;
                u1_b = (u1_top_dc_csbp >> u1_uv) & 0x01;
                u4_ctx_inc = (u1_a + (u1_b << 1));

                ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                        u1_cbf,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table + CBF
                                                + (CHROMA_DC_CTXCAT << 2)
                                                + u4_ctx_inc);
            }

            if (u1_cbf)
            {
                ih264e_cabac_write_coeff4x4(pi2_res_block,
                                            u1_nnz,
                                            3,
                                            u2_sig_coeff_map,
                                            COEFF_ABS_LEVEL_MINUS1
                                                + COEFF_ABS_LEVEL_CAT_3_OFFSET,
                                             ps_cabac_ctxt->au1_cabac_ctxt_table
                                                + SIGNIFICANT_COEFF_FLAG_FRAME
                                                + SIG_COEFF_CTXT_CAT_3_OFFSET,
                                              ps_cabac_ctxt);

                SETBIT(u1_top_dc_csbp, u1_uv);
                SETBIT(u1_left_dc_csbp, u1_uv);
            }
            else
            {
                CLEARBIT(u1_top_dc_csbp, u1_uv);
                CLEARBIT(u1_left_dc_csbp, u1_uv);
            }
        }
        /*************************************************************/
        /*      Update the DC csbp                                   */
        /*************************************************************/
        ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x1;
        ps_curr_ctxt->u1_yuv_dc_csbp &= 0x1;
        ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] |= (u1_left_dc_csbp << 1);
        ps_curr_ctxt->u1_yuv_dc_csbp |= (u1_top_dc_csbp << 1);
    }
    /*******************/
    /* Write Chroma AC */
    /*******************/
    {
        if (u1_chroma_cbp == 2)
        {
            UWORD8 u1_uv_blkno, u1_left_ac_csbp, u1_top_ac_csbp;
            WORD16 *pi2_res_block;
            u1_left_ac_csbp = ps_cabac_ctxt->pu1_left_uv_ac_csbp[0];
            u1_top_ac_csbp = ps_top_ctxt_mb_info->u1_yuv_ac_csbp >> 4;

            for (u1_uv_blkno = 0; u1_uv_blkno < 8; u1_uv_blkno++)
            {
                UWORD8 u1_cbf;
                UWORD8 u1_b2b0, u1_b2b1;
                PARSE_COEFF_DATA_BLOCK_4x4(pv_mb_coeff_data, ps_mb_coeff_data,
                                           u1_nnz, u2_sig_coeff_map,
                                           pi2_res_block);

                u1_cbf = !!(u1_nnz);
                u1_b2b0 = ((u1_uv_blkno & 0x4) >> 1) | (u1_uv_blkno & 0x1);
                u1_b2b1 = ((u1_uv_blkno & 0x4) >> 1)
                                | ((u1_uv_blkno & 0x2) >> 1);

                {
                    UWORD8 u1_a, u1_b;
                    UWORD32 u4_ctx_inc;
                    /* write coded_block_flag */
                    u1_a = (u1_left_ac_csbp >> u1_b2b1) & 0x1;
                    u1_b = (u1_top_ac_csbp >> u1_b2b0) & 0x1;
                    u4_ctx_inc = u1_a + (u1_b << 1);

                    ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                            u1_cbf,
                                            ps_cabac_ctxt->au1_cabac_ctxt_table + CBF
                                                    + (CHROMA_AC_CTXCAT << 2)
                                                    + u4_ctx_inc);

                }
                if (u1_cbf)
                {
                    ih264e_cabac_write_coeff4x4(pi2_res_block,
                                                u1_nnz,
                                                14,
                                                u2_sig_coeff_map,
                                                COEFF_ABS_LEVEL_MINUS1
                                                    + COEFF_ABS_LEVEL_CAT_4_OFFSET,
                                                ps_cabac_ctxt->au1_cabac_ctxt_table
                                                    + +SIGNIFICANT_COEFF_FLAG_FRAME
                                                    + SIG_COEFF_CTXT_CAT_4_OFFSET,
                                                ps_cabac_ctxt);

                    SETBIT(u1_left_ac_csbp, u1_b2b1);
                    SETBIT(u1_top_ac_csbp, u1_b2b0);
                }
                else
                {
                    CLEARBIT(u1_left_ac_csbp, u1_b2b1);
                    CLEARBIT(u1_top_ac_csbp, u1_b2b0);

                }
            }
            /*************************************************************/
            /*      Update the AC csbp                                   */
            /*************************************************************/
            ps_cabac_ctxt->pu1_left_uv_ac_csbp[0] = u1_left_ac_csbp;
            ps_curr_ctxt->u1_yuv_ac_csbp &= 0x0f;
            ps_curr_ctxt->u1_yuv_ac_csbp |= (u1_top_ac_csbp << 4);
        }
        else
        {
            ps_cabac_ctxt->pu1_left_uv_ac_csbp[0] = 0;
            ps_curr_ctxt->u1_yuv_ac_csbp &= 0xf;
        }
    }
    ps_ent_ctxt->pv_mb_coeff_data = pv_mb_coeff_data;
}

/**
*******************************************************************************
* @brief
*  Encodes Residues for the MB as defined in 7.3.5.3
*
* @param[in] ps_ent_ctxt
*  Pointer to entropy context structure
*
* @param[in] u1_cbp
*  coded block pattern
*
* @param[in] u1_ctx_cat
*  Context category, LUMA_AC_CTXCAT or LUMA_4x4_CTXCAT
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_encode_residue(entropy_ctxt_t *ps_ent_ctxt,
                                        UWORD32 u4_cbp, UWORD8 u1_ctx_cat)
{
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    tu_sblk_coeff_data_t *ps_mb_coeff_data;
    void *pv_mb_coeff_data = ps_ent_ctxt->pv_mb_coeff_data;
    UWORD16 u2_sig_coeff_map;
    UWORD8 u1_nnz;
    mb_info_ctxt_t *ps_curr_ctxt;
    mb_info_ctxt_t *ps_top_ctxt;
    UWORD8 u1_left_ac_csbp;
    UWORD8 u1_top_ac_csbp;
    UWORD32 u4_ctx_idx_offset_sig_coef, u4_ctx_idx_offset_abs_lvl;

    ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;
    ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
    u1_left_ac_csbp = ps_cabac_ctxt->pu1_left_y_ac_csbp[0];
    u1_top_ac_csbp = ps_top_ctxt->u1_yuv_ac_csbp;

    if (u4_cbp & 0xf)
    {
        /*  Write luma residue  */
        UWORD8 u1_offset;
        WORD16 *pi2_res_block;
        UWORD8 u1_subblk_num;
        if (u1_ctx_cat == LUMA_AC_CTXCAT)
        {
            u1_offset = 1;
            u4_ctx_idx_offset_sig_coef = SIG_COEFF_CTXT_CAT_1_OFFSET;
            u4_ctx_idx_offset_abs_lvl = COEFF_ABS_LEVEL_MINUS1
                                      + COEFF_ABS_LEVEL_CAT_1_OFFSET;
        }
        else
        {
            u1_offset = 0;
            u4_ctx_idx_offset_sig_coef = SIG_COEFF_CTXT_CAT_2_OFFSET;
            u4_ctx_idx_offset_abs_lvl = COEFF_ABS_LEVEL_MINUS1
                                        + COEFF_ABS_LEVEL_CAT_2_OFFSET;
        }

        for (u1_subblk_num = 0; u1_subblk_num < 16; u1_subblk_num++)
        {
            UWORD8 u1_b0, u1_b1, u1_b2, u1_b3, u1_b2b0, u1_b3b1, u1_b3b2;
            u1_b0 = (u1_subblk_num & 0x1);
            u1_b1 = (u1_subblk_num & 0x2) >> 1;
            u1_b2 = (u1_subblk_num & 0x4) >> 2;
            u1_b3 = (u1_subblk_num & 0x8) >> 3;
            u1_b2b0 = (u1_b2 << 1) | (u1_b0);
            u1_b3b1 = (u1_b3 << 1) | (u1_b1);
            u1_b3b2 = (u1_b3 << 1) | (u1_b2);

            if (!((u4_cbp >> u1_b3b2) & 0x1))
            {
                /************************************************************/
                /* The current block is not coded so skip all the sub block */
                /* and set the pointer of scan level, csbp accrodingly      */
                /************************************************************/
                CLEARBIT(u1_top_ac_csbp, u1_b2b0);
                CLEARBIT(u1_top_ac_csbp, (u1_b2b0 + 1));
                CLEARBIT(u1_left_ac_csbp, u1_b3b1);
                CLEARBIT(u1_left_ac_csbp, (u1_b3b1 + 1));

                u1_subblk_num += 3;
            }
            else
            {
                UWORD8 u1_csbf;

                PARSE_COEFF_DATA_BLOCK_4x4(pv_mb_coeff_data, ps_mb_coeff_data,
                                           u1_nnz, u2_sig_coeff_map,
                                           pi2_res_block);

                u1_csbf = !!(u1_nnz);
                {
                    UWORD8 u1_a, u1_b;
                    UWORD32 u4_ctx_inc;
                    u1_b = (u1_top_ac_csbp >> u1_b2b0) & 0x01;
                    u1_a = (u1_left_ac_csbp >> u1_b3b1) & 0x01;
                    u4_ctx_inc = u1_a + (u1_b << 1);

                    /* Encode the bin */
                    ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                            u1_csbf,
                                            ps_cabac_ctxt->au1_cabac_ctxt_table + CBF
                                                + (u1_ctx_cat << 2) + u4_ctx_inc);

                }
                /**************************/
                /* Write coded_block_flag */
                /**************************/
                if (u1_csbf)
                {
                    ih264e_cabac_write_coeff4x4(pi2_res_block,
                                                u1_nnz,
                                                (UWORD8) (15 - u1_offset),
                                                u2_sig_coeff_map,
                                                u4_ctx_idx_offset_abs_lvl,
                                                ps_cabac_ctxt->au1_cabac_ctxt_table
                                                    + SIGNIFICANT_COEFF_FLAG_FRAME
                                                        + u4_ctx_idx_offset_sig_coef,
                                                ps_cabac_ctxt);

                    SETBIT(u1_top_ac_csbp, u1_b2b0);
                    SETBIT(u1_left_ac_csbp, u1_b3b1);
                }
                else
                {
                    CLEARBIT(u1_top_ac_csbp, u1_b2b0);
                    CLEARBIT(u1_left_ac_csbp, u1_b3b1);
                }
            }
        }
        /**************************************************************************/
        /*                   Update the AC csbp                                   */
        /**************************************************************************/
        ps_cabac_ctxt->pu1_left_y_ac_csbp[0] = u1_left_ac_csbp & 0xf;
        u1_top_ac_csbp &= 0x0f;
        ps_curr_ctxt->u1_yuv_ac_csbp &= 0xf0;
        ps_curr_ctxt->u1_yuv_ac_csbp |= u1_top_ac_csbp;
    }
    else
    {
        ps_cabac_ctxt->pu1_left_y_ac_csbp[0] = 0;
        ps_curr_ctxt->u1_yuv_ac_csbp &= 0xf0;
    }

    /*     Write chroma residue */
    ps_ent_ctxt->pv_mb_coeff_data = pv_mb_coeff_data;
    {
        UWORD8 u1_cbp_chroma;
        u1_cbp_chroma = u4_cbp >> 4;
        if (u1_cbp_chroma)
        {
            ih264e_cabac_write_chroma_residue(ps_ent_ctxt, u1_cbp_chroma);
        }
        else
        {
            ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x1;
            ps_curr_ctxt->u1_yuv_dc_csbp &= 0x1;
            ps_cabac_ctxt->pu1_left_uv_ac_csbp[0] = 0;
            ps_curr_ctxt->u1_yuv_ac_csbp &= 0xf;
        }
    }
}

/**
*******************************************************************************
* @brief
*  Encodes a Motion vector (Sec. 9.3.3.1.1.7 ITU T. H264)
*
* @param[in] u1_mvd
*  Motion vector to be encoded
*
* @param[in] u4_ctx_idx_offset
*  ctxIdxOffset for MV_X or MV_Ycontext
*
* @param[in]  ui2_abs_mvd
*  sum of absolute value of corresponding neighboring motion vectors
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_ctx_mvd(WORD16 u1_mvd, UWORD32 u4_ctx_idx_offset,
                                     UWORD16 ui2_abs_mvd,
                                     cabac_ctxt_t *ps_cabac_ctxt)
{
    UWORD8  u1_bin, u1_ctxt_inc;
    WORD8 k = 3, u1_coff = 9;
    WORD16 i2_abs_mvd, i2_sufs;
    UWORD32 u4_ctx_inc;
    UWORD32 u4_bins;
    WORD8 i1_bins_len;

    if (ui2_abs_mvd < 3)
        u4_ctx_inc = 0;
    else if (ui2_abs_mvd > 32)
        u4_ctx_inc = 2;
    else
        u4_ctx_inc = 1;

    u4_bins = 0;
    i1_bins_len = 1;

    if (u1_mvd == 0)
    {
        ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                0,
                                ps_cabac_ctxt->au1_cabac_ctxt_table + u4_ctx_idx_offset
                                        + u4_ctx_inc);
    }
    else
    {
        i2_abs_mvd = ABS(u1_mvd);
        if (i2_abs_mvd >= u1_coff)
        {
            /* Prefix TU i.e string of 9 1's */
            u4_bins = 0x1ff;
            i1_bins_len = 9;
            u4_ctx_inc = (u4_ctx_inc | 0x065430);

            ih264e_encode_decision_bins(u4_bins,
                                        i1_bins_len,
                                        u4_ctx_inc,
                                        4,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + u4_ctx_idx_offset,
                                        ps_cabac_ctxt);

            /* Suffix, uses EncodeBypass */
            u4_bins = 0;
            i1_bins_len = 0;
            i2_sufs = i2_abs_mvd - u1_coff;
            while (1)
            {
                if (i2_sufs >= (1 << k))
                {
                    u4_bins = (u4_bins | (1 << (31 - i1_bins_len)));
                    i1_bins_len++;
                    i2_sufs = i2_sufs - (1 << k);
                    k++;
                }
                else
                {
                    i1_bins_len++;
                    while (k--)
                    {
                        u1_bin = ((i2_sufs >> k) & 0x01);
                        u4_bins = (u4_bins | (u1_bin << (31 - i1_bins_len)));
                        i1_bins_len++;
                    }
                    break;
                }
            }
            u4_bins >>= (32 - i1_bins_len);
            ih264e_cabac_encode_bypass_bins(ps_cabac_ctxt, u4_bins,
                                            i1_bins_len);
        }
        else
        {
            /* Prefix only */
            /* b0 */
            u4_bins = 1;
            i2_abs_mvd--;
            u1_ctxt_inc = 3;
            while (i2_abs_mvd)
            {
                i2_abs_mvd--;
                u4_bins = (u4_bins | (1 << i1_bins_len));
                if (u1_ctxt_inc <= 6)
                {
                    u4_ctx_inc = (u4_ctx_inc
                                    | (u1_ctxt_inc << (i1_bins_len << 2)));
                    u1_ctxt_inc++;
                }
                i1_bins_len++;
            }
            /* Encode Terminating bit */
            if (i1_bins_len <= 4)
                u4_ctx_inc = (u4_ctx_inc | (u1_ctxt_inc << (i1_bins_len << 2)));
            i1_bins_len++;
            ih264e_encode_decision_bins(u4_bins,
                                        i1_bins_len,
                                        u4_ctx_inc,
                                        4,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + u4_ctx_idx_offset,
                                        ps_cabac_ctxt);
        }
        /* sign bit, uses EncodeBypass */
        if (u1_mvd > 0)
            ih264e_cabac_encode_bypass_bin(ps_cabac_ctxt, 0);
        else
            ih264e_cabac_encode_bypass_bin(ps_cabac_ctxt, 1);
    }
}

/**
*******************************************************************************
* @brief
*  Encodes all motion vectors for a P16x16 MB
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @param[in] pi2_mv_ptr
*  Pointer to array of motion vectors
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_mvds_p16x16(cabac_ctxt_t *ps_cabac_ctxt,
                                         WORD16 *pi2_mv_ptr)
{
    /* Encode the differential component of the motion vectors */
    {
        UWORD8 u1_abs_mvd_x, u1_abs_mvd_y;
        UWORD8 *pu1_top_mv_ctxt, *pu1_lft_mv_ctxt;
        WORD16 u2_mv;

        u1_abs_mvd_x = 0;
        u1_abs_mvd_y = 0;
        pu1_top_mv_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_mv[0];
        pu1_lft_mv_ctxt = ps_cabac_ctxt->pu1_left_mv_ctxt_inc[0];
        {
            UWORD16 u2_abs_mvd_x_a, u2_abs_mvd_x_b, u2_abs_mvd_y_a,
                            u2_abs_mvd_y_b;
            u2_abs_mvd_x_b = (UWORD16) pu1_top_mv_ctxt[0];
            u2_abs_mvd_y_b = (UWORD16) pu1_top_mv_ctxt[1];
            u2_abs_mvd_x_a = (UWORD16) pu1_lft_mv_ctxt[0];
            u2_abs_mvd_y_a = (UWORD16) pu1_lft_mv_ctxt[1];
            u2_mv = *(pi2_mv_ptr++);

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_X,
                                    (UWORD16) (u2_abs_mvd_x_a + u2_abs_mvd_x_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_x = CLIP3(0, 127, ABS(u2_mv));
            u2_mv = *(pi2_mv_ptr++);

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_Y,
                                    (UWORD16) (u2_abs_mvd_y_a + u2_abs_mvd_y_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_y = CLIP3(0, 127, ABS(u2_mv));
        }
        /***************************************************************/
        /* Store abs_mvd_values cabac contexts                         */
        /***************************************************************/
        pu1_top_mv_ctxt[0] = pu1_lft_mv_ctxt[0] = u1_abs_mvd_x;
        pu1_top_mv_ctxt[1] = pu1_lft_mv_ctxt[1] = u1_abs_mvd_y;
    }
}

/**
*******************************************************************************
* @brief
*  Encodes all motion vectors for a B MB (Assumes that mbype is B_L0_16x16,
*  B_L1_16x16 or B_Bi_16x16
*
* @param[in] ps_cabac_ctxt
*  Pointer to cabac context structure
*
* @param[in] pi2_mv_ptr
*  Pointer to array of motion vectors
*
* @returns none
*
* @remarks none
*
*******************************************************************************
*/
static void ih264e_cabac_enc_mvds_b16x16(cabac_ctxt_t *ps_cabac_ctxt,
                                         WORD16 *pi2_mv_ptr,
                                         WORD32 i4_mb_part_pred_mode )
{
    /* Encode the differential component of the motion vectors */
    {
        UWORD8 u1_abs_mvd_x, u1_abs_mvd_y;
        UWORD8 *pu1_top_mv_ctxt, *pu1_lft_mv_ctxt;
        WORD16 u2_mv;

        u1_abs_mvd_x = 0;
        u1_abs_mvd_y = 0;
        pu1_top_mv_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_mv[0];
        pu1_lft_mv_ctxt = ps_cabac_ctxt->pu1_left_mv_ctxt_inc[0];
        if (i4_mb_part_pred_mode != PRED_L1)/* || PRED_BI */
        {
            UWORD16 u2_abs_mvd_x_a, u2_abs_mvd_x_b, u2_abs_mvd_y_a,
                            u2_abs_mvd_y_b;
            u2_abs_mvd_x_b = (UWORD16) pu1_top_mv_ctxt[0];
            u2_abs_mvd_y_b = (UWORD16) pu1_top_mv_ctxt[1];
            u2_abs_mvd_x_a = (UWORD16) pu1_lft_mv_ctxt[0];
            u2_abs_mvd_y_a = (UWORD16) pu1_lft_mv_ctxt[1];
            u2_mv = pi2_mv_ptr[0];

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_X,
                                    (UWORD16) (u2_abs_mvd_x_a + u2_abs_mvd_x_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_x = CLIP3(0, 127, ABS(u2_mv));
            u2_mv = pi2_mv_ptr[1];

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_Y,
                                    (UWORD16) (u2_abs_mvd_y_a + u2_abs_mvd_y_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_y = CLIP3(0, 127, ABS(u2_mv));
        }

        /***************************************************************/
        /* Store abs_mvd_values cabac contexts                         */
        /***************************************************************/
        pu1_top_mv_ctxt[0] = pu1_lft_mv_ctxt[0] = u1_abs_mvd_x;
        pu1_top_mv_ctxt[1] = pu1_lft_mv_ctxt[1] = u1_abs_mvd_y;

        u1_abs_mvd_x = 0;
        u1_abs_mvd_y = 0;
        if (i4_mb_part_pred_mode != PRED_L0)/* || PRED_BI */
        {
            UWORD16 u2_abs_mvd_x_a, u2_abs_mvd_x_b, u2_abs_mvd_y_a,
                            u2_abs_mvd_y_b;
            u2_abs_mvd_x_b = (UWORD16) pu1_top_mv_ctxt[2];
            u2_abs_mvd_y_b = (UWORD16) pu1_top_mv_ctxt[3];
            u2_abs_mvd_x_a = (UWORD16) pu1_lft_mv_ctxt[2];
            u2_abs_mvd_y_a = (UWORD16) pu1_lft_mv_ctxt[3];
            u2_mv = pi2_mv_ptr[2];

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_X,
                                    (UWORD16) (u2_abs_mvd_x_a + u2_abs_mvd_x_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_x = CLIP3(0, 127, ABS(u2_mv));
            u2_mv = pi2_mv_ptr[3];

            ih264e_cabac_enc_ctx_mvd(u2_mv, MVD_Y,
                                    (UWORD16) (u2_abs_mvd_y_a + u2_abs_mvd_y_b),
                                    ps_cabac_ctxt);

            u1_abs_mvd_y = CLIP3(0, 127, ABS(u2_mv));
        }
        /***************************************************************/
        /* Store abs_mvd_values cabac contexts                         */
        /***************************************************************/
        pu1_top_mv_ctxt[2] = pu1_lft_mv_ctxt[2] = u1_abs_mvd_x;
        pu1_top_mv_ctxt[3] = pu1_lft_mv_ctxt[3] = u1_abs_mvd_y;
    }
}

/**
*******************************************************************************
*
* @brief
*  This function generates CABAC coded bit stream for an Intra Slice.
*
* @description
*  The mb syntax layer for intra slices constitutes luma mb mode, mb qp delta,
*  coded block pattern, chroma mb mode and  luma/chroma residue. These syntax
*  elements are written as directed by table 7.3.5 of h264 specification.
*
* @param[in] ps_ent_ctxt
*  pointer to entropy context
*
* @returns error code
*
* @remarks none
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_write_islice_mb_cabac(entropy_ctxt_t *ps_ent_ctxt)
{
    bitstrm_t *ps_bitstream = ps_ent_ctxt->ps_bitstrm;
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    UWORD8 *pu1_byte = ps_ent_ctxt->pv_mb_header_data;
    mb_hdr_common_t *ps_mb_hdr = (mb_hdr_common_t *)ps_ent_ctxt->pv_mb_header_data;
    mb_info_ctxt_t *ps_curr_ctxt;
    WORD32 mb_tpm, mb_type, cbp, chroma_intra_mode, luma_intra_mode;
    WORD8 mb_qp_delta;
    UWORD32 u4_cbp_l, u4_cbp_c;
    WORD32 bitstream_start_offset, bitstream_end_offset;

    if ((ps_bitstream->u4_strm_buf_offset + MIN_STREAM_SIZE_MB)
                    >= ps_bitstream->u4_max_strm_size)
    {
        /* return without corrupting the buffer beyond its size */
        return (IH264E_BITSTREAM_BUFFER_OVERFLOW);
    }
    /* mb header info */
    mb_tpm = ps_mb_hdr->u1_mb_type_mode;
    cbp = ps_mb_hdr->u1_cbp;
    mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;

    /* mb type */
    mb_type = mb_tpm & 0xF;

    ih264e_get_cabac_context(ps_ent_ctxt, mb_type);
    ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;

    /* Starting bitstream offset for header in bits */
    bitstream_start_offset = GET_NUM_BITS(ps_bitstream);
    u4_cbp_c = (cbp >> 4);
    u4_cbp_l = (cbp & 0xF);
    if (mb_type == I16x16)
    {
        luma_intra_mode = ((mb_tpm >> 4) & 3) + 1 + (u4_cbp_c << 2)
                        + (u4_cbp_l == 15) * 12;
    }
    else
    {
        luma_intra_mode = 0;
    }

    chroma_intra_mode = (mb_tpm >> 6);

    /* Encode Intra pred mode, Luma */
    ih264e_cabac_enc_intra_mb_type(ISLICE, luma_intra_mode, ps_cabac_ctxt,
                                   MB_TYPE_I_SLICE);

    if (mb_type == I4x4)
    {
        /* Encode 4x4 MB modes */
        mb_hdr_i4x4_t *ps_mb_hdr_i4x4 = (mb_hdr_i4x4_t *)ps_ent_ctxt->pv_mb_header_data;
        ih264e_cabac_enc_4x4mb_modes(ps_cabac_ctxt, ps_mb_hdr_i4x4->au1_sub_blk_modes);
    }
    /* Encode chroma mode */
    ih264e_cabac_enc_chroma_predmode(chroma_intra_mode, ps_cabac_ctxt);

    if (mb_type != I16x16)
    { /* Encode MB cbp */
        ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);
    }

    if ((cbp > 0) || (mb_type == I16x16))
    {
        /* Encode mb_qp_delta */
        ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);
        /* Ending bitstream offset for header in bits */
        bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
        ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                        - bitstream_start_offset;
        /* Starting bitstream offset for residue */
        bitstream_start_offset = bitstream_end_offset;
        if (mb_type == I16x16)
        {
            ps_curr_ctxt->u1_mb_type = CAB_I16x16;
            ps_curr_ctxt->u1_cbp = cbp;
            ih264e_cabac_encode_residue_luma_dc(ps_ent_ctxt);
            ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_AC_CTXCAT);
        }
        else
        {
            ps_curr_ctxt->u1_cbp = cbp;
            ps_curr_ctxt->u1_mb_type = I4x4;
            ps_curr_ctxt->u1_mb_type = CAB_I4x4;
            ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_4X4_CTXCAT);
            ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
            ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_yuv_dc_csbp &= 0x6;
        }
        /* Ending bitstream offset for reside in bits */
        bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
        ps_ent_ctxt->u4_residue_bits[0] += bitstream_end_offset
                        - bitstream_start_offset;
    }
    else
    {
        ps_curr_ctxt->u1_yuv_ac_csbp = 0;
        ps_curr_ctxt->u1_yuv_dc_csbp = 0;
        *(ps_cabac_ctxt->pu1_left_uv_ac_csbp) = 0;
        *(ps_cabac_ctxt->pu1_left_y_ac_csbp) = 0;
        *(ps_cabac_ctxt->pu1_left_yuv_dc_csbp) = 0;
        ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = 0;
        /* Ending bitstream offset for header in bits */
        bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
        ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                        - bitstream_start_offset;

        /* Computing the number of used used for encoding the MB syntax */
    }
    memset(ps_curr_ctxt->u1_mv, 0, 16);
    memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);
    ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_cbp = cbp;

    if (mb_type == I16x16)
    {
        ps_curr_ctxt->u1_mb_type = CAB_I16x16;
        pu1_byte += sizeof(mb_hdr_i16x16_t);
    }
    else
    {
        ps_curr_ctxt->u1_mb_type = CAB_I4x4;
        pu1_byte += sizeof(mb_hdr_i4x4_t);
    }
    ps_ent_ctxt->pv_mb_header_data = pu1_byte;
    return IH264E_SUCCESS;
}

/**
*******************************************************************************
*
* @brief
*  This function generates CABAC coded bit stream for Inter slices
*
* @description
*  The mb syntax layer for inter slices constitutes luma mb mode, mb qp delta,
*  coded block pattern, chroma mb mode and luma/chroma residue. These syntax
*  elements are written as directed by table 7.3.5 of h264 specification
*
* @param[in] ps_ent_ctxt
*  pointer to entropy context
*
* @returns error code
*
* @remarks none
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_write_pslice_mb_cabac(entropy_ctxt_t *ps_ent_ctxt)
{
    bitstrm_t *ps_bitstream = ps_ent_ctxt->ps_bitstrm;
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    mb_info_ctxt_t *ps_curr_ctxt;
    WORD32 bitstream_start_offset, bitstream_end_offset;
    WORD32 mb_tpm, mb_type, cbp, chroma_intra_mode, luma_intra_mode;
    WORD8 mb_qp_delta;
    UWORD32 u4_cbp_l, u4_cbp_c;
    UWORD8 *pu1_byte = ps_ent_ctxt->pv_mb_header_data;
    mb_hdr_common_t *ps_mb_hdr = (mb_hdr_common_t *)ps_ent_ctxt->pv_mb_header_data;

    if ((ps_bitstream->u4_strm_buf_offset + MIN_STREAM_SIZE_MB)
                    >= ps_bitstream->u4_max_strm_size)
    {
        /* return without corrupting the buffer beyond its size */
        return (IH264E_BITSTREAM_BUFFER_OVERFLOW);
    }
    /* mb header info */
    mb_tpm = ps_mb_hdr->u1_mb_type_mode;

    /* mb type */
    mb_type = mb_tpm & 0xF;
    /* CABAC contexts for the MB */
    ih264e_get_cabac_context(ps_ent_ctxt, mb_type);
    ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;

    /* if Intra MB */
    if (mb_type == I16x16 || mb_type == I4x4)
    {
        cbp = ps_mb_hdr->u1_cbp;
        mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;

        /* Starting bitstream offset for header in bits */
        bitstream_start_offset = GET_NUM_BITS(ps_bitstream);

        /* Encode mb_skip_flag */
        ih264e_cabac_enc_mb_skip(0, ps_cabac_ctxt, MB_SKIP_FLAG_P_SLICE);
        u4_cbp_c = (cbp >> 4);
        u4_cbp_l = (cbp & 0xF);
        if (mb_type == I16x16)
        {
            luma_intra_mode = ((mb_tpm >> 4) & 3) + 1 + (u4_cbp_c << 2)
                            + (u4_cbp_l == 15) * 12;
        }
        else
        {
            luma_intra_mode = 0;
        }
        /* Encode intra mb type */
        {
            ih264e_cabac_encode_bin(ps_cabac_ctxt,
                                    1,
                                    ps_cabac_ctxt->au1_cabac_ctxt_table
                                        + MB_TYPE_P_SLICE);

            ih264e_cabac_enc_intra_mb_type(PSLICE, (UWORD8) luma_intra_mode,
                                           ps_cabac_ctxt, MB_TYPE_P_SLICE);
        }

        if (mb_type == I4x4)
        {
            /* Intra 4x4 modes */
            mb_hdr_i4x4_t *ps_mb_hdr_i4x4 = (mb_hdr_i4x4_t *)ps_ent_ctxt->pv_mb_header_data;
            ih264e_cabac_enc_4x4mb_modes(ps_cabac_ctxt, ps_mb_hdr_i4x4->au1_sub_blk_modes);
        }
        chroma_intra_mode = (mb_tpm >> 6);

        ih264e_cabac_enc_chroma_predmode(chroma_intra_mode, ps_cabac_ctxt);

        if (mb_type != I16x16)
        {
            /* encode CBP */
            ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);
        }

        if ((cbp > 0) || (mb_type == I16x16))
        {
            ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */
            bitstream_start_offset = bitstream_end_offset;

            /* Encoding Residue */
            if (mb_type == I16x16)
            {
                ps_curr_ctxt->u1_mb_type = CAB_I16x16;
                ps_curr_ctxt->u1_cbp = (UWORD8) cbp;
                ih264e_cabac_encode_residue_luma_dc(ps_ent_ctxt);
                ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_AC_CTXCAT);
            }
            else
            {
                ps_curr_ctxt->u1_cbp = (UWORD8) cbp;
                ps_curr_ctxt->u1_mb_type = I4x4;
                ps_curr_ctxt->u1_mb_type = CAB_I4x4;
                ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_4X4_CTXCAT);
                ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
                ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_yuv_dc_csbp &= 0x6;
            }

            /* Ending bitstream offset for reside in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_residue_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
        }
        else
        {
            ps_curr_ctxt->u1_yuv_ac_csbp = 0;
            ps_curr_ctxt->u1_yuv_dc_csbp = 0;
            *(ps_cabac_ctxt->pu1_left_uv_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_y_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_yuv_dc_csbp) = 0;
            ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = 0;
            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
        }

        memset(ps_curr_ctxt->u1_mv, 0, 16);
        memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);
        ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_cbp = (UWORD8) cbp;

        if (mb_type == I16x16)
        {
            ps_curr_ctxt->u1_mb_type = CAB_I16x16;
            pu1_byte += sizeof(mb_hdr_i16x16_t);
        }
        else
        {
            ps_curr_ctxt->u1_mb_type = CAB_I4x4;
            pu1_byte += sizeof(mb_hdr_i4x4_t);
        }

        ps_ent_ctxt->pv_mb_header_data = pu1_byte;

        return IH264E_SUCCESS;
    }
    else /* Inter MB */
    {
        /* Starting bitstream offset for header in bits */
        bitstream_start_offset = GET_NUM_BITS(ps_bitstream);
        /* Encoding P16x16 */
        if (mb_type != PSKIP)
        {
            mb_hdr_p16x16_t *ps_mb_hdr_p16x16 = (mb_hdr_p16x16_t *)ps_ent_ctxt->pv_mb_header_data;
            cbp = ps_mb_hdr->u1_cbp;
            mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;

            /* Encoding mb_skip */
            ih264e_cabac_enc_mb_skip(0, ps_cabac_ctxt, MB_SKIP_FLAG_P_SLICE);

            /* Encoding mb_type as P16x16 */
            {
                UWORD32 u4_ctx_inc_p;
                u4_ctx_inc_p = (0x010 + ((2) << 8));

                ih264e_encode_decision_bins(0, 3, u4_ctx_inc_p, 3,
                                            &(ps_cabac_ctxt->au1_cabac_ctxt_table[MB_TYPE_P_SLICE]),
                                            ps_cabac_ctxt);
            }
            ps_curr_ctxt->u1_mb_type = CAB_P;
            {
                WORD16 *pi2_mv_ptr = (WORD16 *) ps_mb_hdr_p16x16->ai2_mv;

                ps_curr_ctxt->u1_mb_type = (ps_curr_ctxt->u1_mb_type
                                            | CAB_NON_BD16x16);
                 /* Encoding motion vector for P16x16 */
                ih264e_cabac_enc_mvds_p16x16(ps_cabac_ctxt, pi2_mv_ptr);
            }
            /* Encode CBP */
            ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);

            if (cbp)
            {
                /* encode mb_qp_delta */
                ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);
            }

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */
            bitstream_start_offset = bitstream_end_offset;

            pu1_byte += sizeof(mb_hdr_p16x16_t);

        }
        else/* MB = PSKIP */
        {
            ih264e_cabac_enc_mb_skip(1, ps_cabac_ctxt, MB_SKIP_FLAG_P_SLICE);

            ps_curr_ctxt->u1_mb_type = CAB_P_SKIP;
            (*ps_ent_ctxt->pi4_mb_skip_run)++;

            memset(ps_curr_ctxt->u1_mv, 0, 16);
            memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);
            cbp = 0;

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */

            pu1_byte += sizeof(mb_hdr_pskip_t);
        }

        if (cbp > 0)
        {
            /* Encode residue */
            ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_4X4_CTXCAT);
            /* Ending bitstream offset for reside in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_residue_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;

            ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
            ps_curr_ctxt->u1_yuv_dc_csbp &= 0x6;
        }
        else
        {
            ps_curr_ctxt->u1_yuv_ac_csbp = 0;
            ps_curr_ctxt->u1_yuv_dc_csbp = 0;
            *(ps_cabac_ctxt->pu1_left_uv_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_y_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_yuv_dc_csbp) = 0;
            ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = 0;
        }
        ps_curr_ctxt->u1_intrapred_chroma_mode = 0;
        ps_curr_ctxt->u1_cbp = cbp;
        ps_ent_ctxt->pv_mb_header_data = pu1_byte;

        return IH264E_SUCCESS;
    }
}

/**
*******************************************************************************
*
* @brief
*  This function generates CABAC coded bit stream for B slices
*
* @description
*  The mb syntax layer for inter slices constitutes luma mb mode, mb qp delta,
*  coded block pattern, chroma mb mode and luma/chroma residue. These syntax
*  elements are written as directed by table 7.3.5 of h264 specification
*
* @param[in] ps_ent_ctxt
*  pointer to entropy context
*
* @returns error code
*
* @remarks none
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_write_bslice_mb_cabac(entropy_ctxt_t *ps_ent_ctxt)
{
    bitstrm_t *ps_bitstream = ps_ent_ctxt->ps_bitstrm;
    cabac_ctxt_t *ps_cabac_ctxt = ps_ent_ctxt->ps_cabac;
    mb_info_ctxt_t *ps_curr_ctxt;
    WORD32 bitstream_start_offset, bitstream_end_offset;
    WORD32 mb_tpm, mb_type, cbp, chroma_intra_mode, luma_intra_mode;
    WORD8 mb_qp_delta;
    UWORD32 u4_cbp_l, u4_cbp_c;
    UWORD8 *pu1_byte = ps_ent_ctxt->pv_mb_header_data;
    mb_hdr_common_t *ps_mb_hdr = (mb_hdr_common_t *)ps_ent_ctxt->pv_mb_header_data;

    if ((ps_bitstream->u4_strm_buf_offset + MIN_STREAM_SIZE_MB)
                    >= ps_bitstream->u4_max_strm_size)
    {
        /* return without corrupting the buffer beyond its size */
        return (IH264E_BITSTREAM_BUFFER_OVERFLOW);
    }
    /* mb header info */
    mb_tpm = ps_mb_hdr->u1_mb_type_mode;

    /* mb type */
    mb_type = mb_tpm & 0xF;
    /* CABAC contexts for the MB */
    ih264e_get_cabac_context(ps_ent_ctxt, mb_type);
    ps_curr_ctxt = ps_cabac_ctxt->ps_curr_ctxt_mb_info;

    /* if Intra MB */
    if (mb_type == I16x16 || mb_type == I4x4)
    {
        cbp = ps_mb_hdr->u1_cbp;
        mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;

        /* Starting bitstream offset for header in bits */
        bitstream_start_offset = GET_NUM_BITS(ps_bitstream);

        /* Encode mb_skip_flag */
        ih264e_cabac_enc_mb_skip(0, ps_cabac_ctxt, MB_SKIP_FLAG_B_SLICE);
        u4_cbp_c = (cbp >> 4);
        u4_cbp_l = (cbp & 0xF);
        if (mb_type == I16x16)
        {
            luma_intra_mode = ((mb_tpm >> 4) & 3) + 1 + (u4_cbp_c << 2)
                            + (u4_cbp_l == 15) * 12;
        }
        else
        {
            luma_intra_mode = 0;
        }
        /* Encode intra mb type */
        {
            mb_info_ctxt_t *ps_left_ctxt = ps_cabac_ctxt->ps_left_ctxt_mb_info;
            mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
            UWORD32 u4_ctx_inc = 0;

            if (ps_left_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                u4_ctx_inc += ((ps_left_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                != CAB_BD16x16) ? 1 : 0;
            if (ps_top_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                u4_ctx_inc += ((ps_top_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                != CAB_BD16x16) ? 1 : 0;

            /* Intra Prefix Only "111101" */
            u4_ctx_inc = (u4_ctx_inc | 0x05555430);
            ih264e_encode_decision_bins(0x2f,
                                        6,
                                        u4_ctx_inc,
                                        3,
                                        ps_cabac_ctxt->au1_cabac_ctxt_table
                                            + MB_TYPE_B_SLICE,
                                        ps_cabac_ctxt);

            ih264e_cabac_enc_intra_mb_type(BSLICE, (UWORD8) luma_intra_mode,
                                           ps_cabac_ctxt, MB_TYPE_B_SLICE);

        }

        if (mb_type == I4x4)
        {
            /* Intra 4x4 modes */
            mb_hdr_i4x4_t *ps_mb_hdr_i4x4 = (mb_hdr_i4x4_t *)ps_ent_ctxt->pv_mb_header_data;
            ih264e_cabac_enc_4x4mb_modes(ps_cabac_ctxt, ps_mb_hdr_i4x4->au1_sub_blk_modes);
        }
        chroma_intra_mode = (mb_tpm >> 6);

        ih264e_cabac_enc_chroma_predmode(chroma_intra_mode, ps_cabac_ctxt);

        if (mb_type != I16x16)
        {
            /* encode CBP */
            ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);
        }

        if ((cbp > 0) || (mb_type == I16x16))
        {
            ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */
            bitstream_start_offset = bitstream_end_offset;

            /* Encoding Residue */
            if (mb_type == I16x16)
            {
                ps_curr_ctxt->u1_mb_type = CAB_I16x16;
                ps_curr_ctxt->u1_cbp = (UWORD8) cbp;
                ih264e_cabac_encode_residue_luma_dc(ps_ent_ctxt);
                ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_AC_CTXCAT);
            }
            else
            {
                ps_curr_ctxt->u1_cbp = (UWORD8) cbp;
                ps_curr_ctxt->u1_mb_type = I4x4;
                ps_curr_ctxt->u1_mb_type = CAB_I4x4;
                ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_4X4_CTXCAT);
                ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
                ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_yuv_dc_csbp &= 0x6;
            }

            /* Ending bitstream offset for reside in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_residue_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
        }
        else
        {
            ps_curr_ctxt->u1_yuv_ac_csbp = 0;
            ps_curr_ctxt->u1_yuv_dc_csbp = 0;
            *(ps_cabac_ctxt->pu1_left_uv_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_y_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_yuv_dc_csbp) = 0;
            ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = 0;
            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[0] += bitstream_end_offset
                            - bitstream_start_offset;
        }

        memset(ps_curr_ctxt->u1_mv, 0, 16);
        memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);
        ps_cabac_ctxt->ps_curr_ctxt_mb_info->u1_cbp = (UWORD8) cbp;

        if (mb_type == I16x16)
        {
            ps_curr_ctxt->u1_mb_type = CAB_I16x16;
            pu1_byte += sizeof(mb_hdr_i16x16_t);
        }
        else
        {
            ps_curr_ctxt->u1_mb_type = CAB_I4x4;
            pu1_byte += sizeof(mb_hdr_i4x4_t);
        }

        ps_ent_ctxt->pv_mb_header_data = pu1_byte;

        return IH264E_SUCCESS;
    }
    else /* Inter MB */
    {
        /* Starting bitstream offset for header in bits */
        bitstream_start_offset = GET_NUM_BITS(ps_bitstream);
        /* Encoding B_Direct_16x16 */
        if (mb_type == BDIRECT)
        {
            cbp = ps_mb_hdr->u1_cbp;
            mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;


            /* Encoding mb_skip */
            ih264e_cabac_enc_mb_skip(0, ps_cabac_ctxt, MB_SKIP_FLAG_B_SLICE);

            /* Encoding mb_type as B_Direct_16x16 */
            {

                mb_info_ctxt_t *ps_left_ctxt =
                                ps_cabac_ctxt->ps_left_ctxt_mb_info;
                mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
                UWORD32 u4_ctx_inc = 0;

                if (ps_left_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                    u4_ctx_inc += ((ps_left_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                    != CAB_BD16x16) ? 1 : 0;
                if (ps_top_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                    u4_ctx_inc += ((ps_top_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                    != CAB_BD16x16) ? 1 : 0;
                /* Encode the bin */
                ih264e_cabac_encode_bin(
                                ps_cabac_ctxt,
                                0,
                                ps_cabac_ctxt->au1_cabac_ctxt_table
                                                + MB_TYPE_B_SLICE + u4_ctx_inc);

            }
            ps_curr_ctxt->u1_mb_type = CAB_BD16x16;
            memset(ps_curr_ctxt->u1_mv, 0, 16);
            memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);

            /* Encode CBP */
            ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);

            if (cbp)
            {
                /* encode mb_qp_delta */
                ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);
            }

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */
            bitstream_start_offset = bitstream_end_offset;
            /* Starting bitstream offset for residue */

            pu1_byte += sizeof(mb_hdr_bdirect_t);
        }
        else if (mb_type == BSKIP)/* MB = BSKIP */
        {
            ih264e_cabac_enc_mb_skip(1, ps_cabac_ctxt, MB_SKIP_FLAG_B_SLICE);

            ps_curr_ctxt->u1_mb_type = CAB_B_SKIP;

            memset(ps_curr_ctxt->u1_mv, 0, 16);
            memset(ps_cabac_ctxt->pu1_left_mv_ctxt_inc, 0, 16);
            cbp = 0;

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */

            pu1_byte += sizeof(mb_hdr_bskip_t);
        }
        else /* mbype is B_L0_16x16, B_L1_16x16 or B_Bi_16x16 */
        {
            mb_hdr_b16x16_t *ps_mb_hdr_b16x16 = (mb_hdr_b16x16_t *)ps_ent_ctxt->pv_mb_header_data;

            WORD32 i4_mb_part_pred_mode = (mb_tpm >> 4);
            UWORD32 u4_mb_type = mb_type - B16x16 + B_L0_16x16
                            + i4_mb_part_pred_mode;
            cbp = ps_mb_hdr->u1_cbp;
            mb_qp_delta = ps_mb_hdr->u1_mb_qp_delta;

            /* Encoding mb_skip */
            ih264e_cabac_enc_mb_skip(0, ps_cabac_ctxt, MB_SKIP_FLAG_B_SLICE);

            /* Encoding mb_type as B16x16 */
            {
                mb_info_ctxt_t *ps_left_ctxt =
                                ps_cabac_ctxt->ps_left_ctxt_mb_info;
                mb_info_ctxt_t *ps_top_ctxt = ps_cabac_ctxt->ps_top_ctxt_mb_info;
                UWORD32 u4_ctx_inc = 0;

                UWORD32 u4_mb_type_bins = u4_b_mb_type[u4_mb_type];
                UWORD32 u4_bin_len = (u4_mb_type_bins >> 8) & 0x0F;
                u4_mb_type_bins = u4_mb_type_bins & 0xFF;

                if (ps_left_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                    u4_ctx_inc += ((ps_left_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                    != CAB_BD16x16) ? 1 : 0;
                if (ps_top_ctxt != ps_cabac_ctxt->ps_def_ctxt_mb_info)
                    u4_ctx_inc += ((ps_top_ctxt->u1_mb_type & CAB_BD16x16_MASK)
                                    != CAB_BD16x16) ? 1 : 0;

                u4_ctx_inc = u4_ctx_inc | ui_b_mb_type_ctx_inc[u4_mb_type];

                ih264e_encode_decision_bins(u4_mb_type_bins,
                                            u4_bin_len,
                                            u4_ctx_inc,
                                            u4_bin_len,
                                            &(ps_cabac_ctxt->au1_cabac_ctxt_table[MB_TYPE_B_SLICE]),
                                            ps_cabac_ctxt);
            }

            ps_curr_ctxt->u1_mb_type = CAB_NON_BD16x16;
            {
                WORD16 *pi2_mv_ptr = (WORD16 *) ps_mb_hdr_b16x16->ai2_mv;

                /* Get the pred modes */
                ps_curr_ctxt->u1_mb_type = (ps_curr_ctxt->u1_mb_type
                                | CAB_NON_BD16x16);
                /* Encoding motion vector for B16x16 */
                ih264e_cabac_enc_mvds_b16x16(ps_cabac_ctxt, pi2_mv_ptr,
                                             i4_mb_part_pred_mode);
            }
            /* Encode CBP */
            ih264e_cabac_enc_cbp(cbp, ps_cabac_ctxt);

            if (cbp)
            {
                /* encode mb_qp_delta */
                ih264e_cabac_enc_mb_qp_delta(mb_qp_delta, ps_cabac_ctxt);
            }

            /* Ending bitstream offset for header in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_header_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;
            /* Starting bitstream offset for residue */
            bitstream_start_offset = bitstream_end_offset;

            pu1_byte += sizeof(mb_hdr_b16x16_t);
        }

        if (cbp > 0)
        {
            /* Encode residue */
            ih264e_cabac_encode_residue(ps_ent_ctxt, cbp, LUMA_4X4_CTXCAT);
            /* Ending bitstream offset for reside in bits */
            bitstream_end_offset = GET_NUM_BITS(ps_bitstream);
            ps_ent_ctxt->u4_residue_bits[1] += bitstream_end_offset
                            - bitstream_start_offset;

            ps_cabac_ctxt->pu1_left_yuv_dc_csbp[0] &= 0x6;
            ps_curr_ctxt->u1_yuv_dc_csbp &= 0x6;
        }
        else
        {
            ps_curr_ctxt->u1_yuv_ac_csbp = 0;
            ps_curr_ctxt->u1_yuv_dc_csbp = 0;
            *(ps_cabac_ctxt->pu1_left_uv_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_y_ac_csbp) = 0;
            *(ps_cabac_ctxt->pu1_left_yuv_dc_csbp) = 0;
            ps_cabac_ctxt->i1_prev_mb_qp_delta_ctxt = 0;
        }
        ps_curr_ctxt->u1_intrapred_chroma_mode = 0;
        ps_curr_ctxt->u1_cbp = cbp;
        ps_ent_ctxt->pv_mb_header_data = pu1_byte;
        return IH264E_SUCCESS;
    }
}
