C++程序  |  2205行  |  74.48 KB

/******************************************************************************
 *
 * 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_utils.c
*
* @brief
*  Contains miscellaneous utility functions used by the encoder
*
* @author
*  ittiam
*
* @par List of Functions:
*  - ih264e_get_min_level()
*  - ih264e_get_lvl_idx()
*  - ih264e_get_dpb_size()
*  - ih264e_get_total_pic_buf_size()
*  - ih264e_get_pic_mv_bank_size()
*  - ih264e_pic_buf_mgr_add_bufs()
*  - ih264e_mv_buf_mgr_add_bufs()
*  - ih264e_init_quant_params()
*  - ih264e_init_air_map()
*  - ih264e_codec_init()
*  - ih264e_pic_init()
*
* @remarks
*  None
*
*******************************************************************************
*/

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

/* system include files */
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

/* user include files */
#include "ih264_typedefs.h"
#include "iv2.h"
#include "ive2.h"
#include "ih264e.h"
#include "ithread.h"
#include "ih264_defs.h"
#include "ih264_size_defs.h"
#include "ime_distortion_metrics.h"
#include "ime_defs.h"
#include "ime_structs.h"
#include "ih264_error.h"
#include "ih264_structs.h"
#include "ih264_trans_quant_itrans_iquant.h"
#include "ih264_inter_pred_filters.h"
#include "ih264_mem_fns.h"
#include "ih264_padding.h"
#include "ih264_intra_pred_filters.h"
#include "ih264_deblk_edge_filters.h"
#include "ih264_cabac_tables.h"
#include "ih264_macros.h"
#include "ih264_common_tables.h"
#include "ih264_debug.h"
#include "ih264_trans_data.h"
#include "ih264e_defs.h"
#include "ih264e_globals.h"
#include "ih264_buf_mgr.h"
#include "ih264_dpb_mgr.h"
#include "ih264e_error.h"
#include "ih264e_bitstream.h"
#include "irc_cntrl_param.h"
#include "irc_frame_info_collector.h"
#include "ih264e_rate_control.h"
#include "ih264e_cabac_structs.h"
#include "ih264e_structs.h"
#include "ih264e_cabac.h"
#include "ih264e_utils.h"
#include "ih264e_config.h"
#include "ih264e_statistics.h"
#include "ih264e_trace.h"
#include "ih264_list.h"
#include "ih264e_encode_header.h"
#include "ih264e_me.h"
#include "ime.h"
#include "ih264e_core_coding.h"
#include "ih264e_rc_mem_interface.h"
#include "ih264e_time_stamp.h"
#include "ih264e_debug.h"
#include "ih264e_process.h"
#include "ih264e_master.h"
#include "irc_rate_control_api.h"
#include "ime_statistics.h"

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

/**
 *******************************************************************************
 *
 * @brief
 *  Queues the current buffer, gets back a another buffer for encoding with corrent
 *  picture type
 *
 * @par Description:
 *      This function performs 3 distinct but related functions.
 *      1) Maintains an input queue [Note the the term queue donot imply a
 *         first-in first-out logic here] that queues input and dequeues them so
 *         that input frames can be encoded at any predetermined encoding order
 *      2) Uses RC library to decide which frame must be encoded in current pass
 *         and which picture type it must be encoded to.
 *      3) Uses RC library to decide the QP at which current frame has to be
 *         encoded
 *      4) Determines if the current picture must be encoded or not based on
 *         PRE-ENC skip
 *
 *     Input queue is used for storing input buffers till they are used for
 *     encoding. This queue is maintained at ps_codec->as_inp_list. Whenever a
 *     valid input comes, it is added to the end of queue. This same input is
 *     added to RC queue using the identifier as ps_codec->i4_pic_cnt. Hence any
 *     pic from RC can be located in the input queue easily.
 *
 *     The dequeue operation does not start till we have ps_codec->s_cfg.u4_max_num_bframes
 *     frames in the queue. THis is done in order to ensure that once output starts
 *     we will have a constant stream of output with no gaps.
 *
 *     THe output frame order is governed by RC library. When ever we dequeue a
 *     buffer from RC library, it ensures that we will get them in encoding order
 *     With the output of RC library, we can use the picture id to dequeue the
 *     corresponding buffer from input queue and encode it.
 *
 *     Condition at the end of stream.
 *     -------------------------------
 *      At the last valid buffer from the app, we will get ps_ive_ip->u4_is_last
 *      to be set. This will the given to lib when appropriate input buffer is
 *      given to encoding.
 *
 *      Since we have to output is not in sync with input, we will have frames to
 *      encode even after we recive the last vaild input buffer. Hence we have to
 *      make sure that we donot queue any new buffers once we get the flag [It may
 *      mess up GOP ?]. This is acheived by setting ps_codec->i4_last_inp_buff_received
 *      to act as a permenent marker for last frame recived [This may not be needed,
 *      because in our current app, all buffers after the last are marked as last.
 *      But can we rely on that?] . Hence after this flgag is set no new buffers are
 *      queued.
 *
 * @param[in] ps_codec
 *   Pointer to codec descriptor
 *
 * @param[in] ps_ive_ip
 *   Current input buffer to the encoder
 *
 * @param[out] ps_inp
 *   Buffer to be encoded in the current pass
 *
 * @returns
 *   Flag indicating if we have a pre-enc skip or not
 *
 * @remarks
 * TODO (bpic)
 *  The check for null ans is last is redudent.
 *  Need to see if we can remove it
 *
 *******************************************************************************
 */
WORD32 ih264e_input_queue_update(codec_t *ps_codec,
                                 ive_video_encode_ip_t *ps_ive_ip,
                                 inp_buf_t *ps_enc_buff)
{

    inp_buf_t *ps_inp_buf;
    picture_type_e e_pictype;
    WORD32 i4_skip;
    UWORD32 ctxt_sel, u4_pic_id, u4_pic_disp_id;
    UWORD8 u1_frame_qp, i;
    UWORD32 max_frame_bits = 0x7FFFFFFF;

    /*  Mark that the last input frame has been received */
    if (ps_ive_ip->u4_is_last == 1)
    {
        ps_codec->i4_last_inp_buff_received = 1;
    }

    if (ps_ive_ip->s_inp_buf.apv_bufs[0] == NULL
                    && !ps_codec->i4_last_inp_buff_received)
    {
        ps_enc_buff->s_raw_buf.apv_bufs[0] = NULL;
        ps_enc_buff->u4_is_last = ps_ive_ip->u4_is_last;
        return 0;
    }

    /***************************************************************************
     * Check for pre enc skip
     *   When src and target frame rates donot match, we skip some frames to
     *   maintain the relation ship between them
     **************************************************************************/
    {
        WORD32 skip_src;

        skip_src = ih264e_update_rc_framerates(
                        ps_codec->s_rate_control.pps_rate_control_api,
                        ps_codec->s_rate_control.pps_pd_frm_rate,
                        ps_codec->s_rate_control.pps_time_stamp,
                        ps_codec->s_rate_control.pps_frame_time);

        if (skip_src)
        {
            ps_enc_buff->u4_is_last = ps_ive_ip->u4_is_last;
            return 1;
        }
    }

    /***************************************************************************
     *Queue the input to the queue
     **************************************************************************/
    ps_inp_buf = &(ps_codec->as_inp_list[ps_codec->i4_pic_cnt
                                         % MAX_NUM_INP_FRAMES]);

    /* copy input info. to internal structure */
    ps_inp_buf->s_raw_buf = ps_ive_ip->s_inp_buf;
    ps_inp_buf->u4_timestamp_low = ps_ive_ip->u4_timestamp_low;
    ps_inp_buf->u4_timestamp_high = ps_ive_ip->u4_timestamp_high;
    ps_inp_buf->u4_is_last = ps_ive_ip->u4_is_last;
    ps_inp_buf->pv_mb_info = ps_ive_ip->pv_mb_info;
    ps_inp_buf->u4_mb_info_type = ps_ive_ip->u4_mb_info_type;
    ps_inp_buf->pv_pic_info = ps_ive_ip->pv_pic_info;
    ps_inp_buf->u4_pic_info_type = ps_ive_ip->u4_pic_info_type;

    /***************************************************************************
     * Now we should add the picture to RC stack here
     **************************************************************************/
    /*
     * If an I frame has been requested, ask  RC to force it
     * For IDR requests, we have to ask RC to force I and set IDR by our selves
     * since RC Donot know about IDR. For forcing an IDR at dequeue stage we
     * should record that an IDR has been requested some where. Hence we will
     * store it in the u4_idr_inp_list at a position same as that of input frame
     */
    {
        WORD32 i4_force_idr, i4_force_i;

        i4_force_idr = (ps_codec->force_curr_frame_type == IV_IDR_FRAME);
        i4_force_idr |= !(ps_codec->i4_pic_cnt % ps_codec->s_cfg.u4_idr_frm_interval);

        i4_force_i = (ps_codec->force_curr_frame_type == IV_I_FRAME);

        ps_codec->i4_pending_idr_flag |= i4_force_idr;

        if ((ps_codec->i4_pic_cnt > 0) && (i4_force_idr || i4_force_i))
        {
            irc_force_I_frame(ps_codec->s_rate_control.pps_rate_control_api);
        }
        ps_codec->force_curr_frame_type = IV_NA_FRAME;
    }

    irc_add_picture_to_stack(ps_codec->s_rate_control.pps_rate_control_api,
                             ps_codec->i4_pic_cnt);


    /* Delay */
    if (ps_codec->i4_encode_api_call_cnt
                    < (WORD32)(ps_codec->s_cfg.u4_num_bframes))
    {
        ps_enc_buff->s_raw_buf.apv_bufs[0] = NULL;
        ps_enc_buff->u4_is_last = 0;
        return 0;
    }

    /***************************************************************************
     * Get a new pic to encode
     **************************************************************************/
    /* Query the picture_type */
    e_pictype = ih264e_rc_get_picture_details(
                    ps_codec->s_rate_control.pps_rate_control_api, (WORD32 *)(&u4_pic_id),
                    (WORD32 *)(&u4_pic_disp_id));

    switch (e_pictype)
    {
        case I_PIC:
            ps_codec->pic_type = PIC_I;
            break;
        case P_PIC:
            ps_codec->pic_type = PIC_P;
            break;
        case B_PIC:
            ps_codec->pic_type = PIC_B;
            break;
        default:
            ps_codec->pic_type = PIC_NA;
            ps_enc_buff->s_raw_buf.apv_bufs[0] = NULL;
            return 0;
    }

    /* Set IDR if it has been requested */
    if (ps_codec->pic_type == PIC_I)
    {
        ps_codec->pic_type = ps_codec->i4_pending_idr_flag ?
                                    PIC_IDR : ps_codec->pic_type;
        ps_codec->i4_pending_idr_flag = 0;
    }

    /* Get current frame Qp */
    u1_frame_qp = (UWORD8)irc_get_frame_level_qp(
                    ps_codec->s_rate_control.pps_rate_control_api, e_pictype,
                    max_frame_bits);
    ps_codec->u4_frame_qp = gau1_mpeg2_to_h264_qmap[u1_frame_qp];

    /*
     * copy the pic id to poc because the display order is assumed to be same
     * as input order
     */
    ps_codec->i4_poc = u4_pic_id;

    /***************************************************************************
     * Now retrieve the correct picture from the queue
     **************************************************************************/

    /* Mark the skip flag   */
    i4_skip = 0;
    ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS;
    ps_codec->s_rate_control.pre_encode_skip[ctxt_sel] = i4_skip;

    /* Get a buffer to encode */
    ps_inp_buf = &(ps_codec->as_inp_list[u4_pic_id % MAX_NUM_INP_FRAMES]);

    /* copy dequeued input to output */
    ps_enc_buff->s_raw_buf = ps_inp_buf->s_raw_buf;
    ps_enc_buff->u4_timestamp_low = ps_inp_buf->u4_timestamp_low;
    ps_enc_buff->u4_timestamp_high = ps_inp_buf->u4_timestamp_high;
    ps_enc_buff->u4_is_last = ps_inp_buf->u4_is_last;
    ps_enc_buff->pv_mb_info = ps_inp_buf->pv_mb_info;
    ps_enc_buff->u4_mb_info_type = ps_inp_buf->u4_mb_info_type;
    ps_enc_buff->pv_pic_info = ps_inp_buf->pv_pic_info;
    ps_enc_buff->u4_pic_info_type = ps_inp_buf->u4_pic_info_type;

    /* Special case for encoding trailing B frames
     *
     * In encoding streams with B frames it may happen that we have a B frame
     * at the end without a P/I frame after it. Hence when we are dequeing from
     * the RC, it will return the P frame [next in display order but before in
     * encoding order] first. Since the dequeue happens for an invalid frame we
     * will get a frame with null buff and set u4_is_last. Hence lib with return
     * last frame flag at this point and will stop encoding.
     *
     * Since for the last B frame, we does not have the forward ref frame
     * it makes sense to force it into P.
     *
     * To solve this, in case the current frame is P and if the last frame flag
     * is set, we need to see if there is and pending B frames. If there are any,
     * we should just encode that picture as the current P frame and set
     * that B frame as the last frame. Hence the encoder will terminate naturally
     * once that B-frame is encoded after all the in between frames.
     *
     * Since we cannot touch RC stack directly, the option of actually swapping
     * frames in RC is ruled out. We have to modify the as_inp_list to simulate
     * such a behavior by RC. We can do that by
     *  1) Search through as_inp_list to locate the largest u4_timestamp_low less
     *     than current u4_timestamp_low. This will give us the last B frame before
     *     the current P frame. Note that this will handle pre encode skip too since
     *     queue happens after pre enc skip.
     *  2) Swap the position in as_inp_list. Hence now the last B frame is
     *     encoded as P frame. And the new last B frame will have u4_is_last
     *     set so that encoder will end naturally once we reached that B frame
     *     or any subsequent frame. Also the current GOP will have 1 less B frame
     *     Since we are swapping, the poc will also be in-order.
     *  3) In case we have an IPP stream, the result of our search will be an
     *     I/P frame which is already encoded. Thus swap and encode will result
     *     in encoding of duplicate frames. Hence to avoid this we will only
     *     have this work around in case of u4_num_bframes > 0.
     *
     *     In case we have forced an I/IDR frame In between this P frame and
     *     the last B frame -> This cannot happen as the current P frame is
     *     supposed to have u4_is_last set. Thus forcing an I/ IDR after this
     *     is illogical.
     *
     *     In cae if we have forced an I such that the frame just before last frame
     *     in is I/P -> This case will never arise. Since we have a closed GOP now,
     *     once we force an I, the gop gets reset, hence there will be a B between
     *     I/P and I/P.
     */
    if (ps_enc_buff->u4_is_last && (ps_codec->pic_type == PIC_P)
                    && ps_codec->s_cfg.u4_num_bframes)
    {
        WORD32 cntr;
        WORD32 lst_bframe = -1;
        UWORD32 u4_timestamp_low = 0;
        UWORD32 u4_timestamp_high = 0;
        inp_buf_t *ps_swap_buff, *ps_inp_list;

        ps_inp_list = &ps_codec->as_inp_list[0];

        /* Now search the inp list for highest timestamp */
        for(cntr = 0; cntr < MAX_NUM_INP_FRAMES; cntr++)
        {
            if(ps_inp_list[cntr].s_raw_buf.apv_bufs[0] != NULL)
            {
                if ((ps_inp_list[cntr].u4_timestamp_high  > u4_timestamp_high) ||
                    (ps_inp_list[cntr].u4_timestamp_high  == u4_timestamp_high &&
                     ps_inp_list[cntr].u4_timestamp_low  > u4_timestamp_low))
                {
                    u4_timestamp_low = ps_inp_list[cntr].u4_timestamp_low;
                    u4_timestamp_high = ps_inp_list[cntr].u4_timestamp_high;
                    lst_bframe = cntr;
                }
            }
        }

        if(lst_bframe != -1)
        {
            ps_swap_buff = &(ps_codec->as_inp_list[lst_bframe]);

            /* copy the last B buffer to output */
            *ps_enc_buff = *ps_swap_buff;

            /* Store the current buf into the queue in place of last B buf */
            *ps_swap_buff = *ps_inp_buf;
        }
    }

    if (ps_enc_buff->u4_is_last)
    {
        ps_codec->pic_type = PIC_NA;
    }

    /* The buffer in the queue is set to NULL to specify that encoding is done for that frame */
    for(i = 0; i < 3; i++)
    {
        ps_inp_buf->s_raw_buf.apv_bufs[i] = NULL;
    }

    /* Return the buffer status */
    return (0);
}

/**
*******************************************************************************
*
* @brief
*  Used to get minimum level index for a given picture size
*
* @par Description:
*  Gets the minimum level index and then gets corresponding level.
*  Also used to ignore invalid levels like 2.3, 3.3 etc
*
* @param[in] level
*  Level of the stream
*
* @returns  Level index for a given level
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_get_min_level(WORD32 wd, WORD32 ht)
{
    WORD32 lvl_idx = MAX_LEVEL, i;
    WORD32 pic_size = wd * ht;
    WORD32 max = MAX(wd, ht);
    for (i = 0; i < MAX_LEVEL; i++)
    {
        if ((pic_size <= gai4_ih264_max_luma_pic_size[i]) &&
            (max <= gai4_ih264_max_wd_ht[i]))
        {
            lvl_idx = i;
            break;
        }
    }

    return gai4_ih264_levels[lvl_idx];
}

/**
*******************************************************************************
*
* @brief
*  Used to get level index for a given level
*
* @par Description:
*  Converts from level_idc (which is multiplied by 30) to an index that can be
*  used as a lookup. Also used to ignore invalid levels like 2.2 , 3.2 etc
*
* @param[in] level
*  Level of the stream
*
* @returns  Level index for a given level
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_get_lvl_idx(WORD32 level)
{
    WORD32 lvl_idx = 0;

    if (level < IH264_LEVEL_11)
    {
        lvl_idx = 0;
    }
    else if (level < IH264_LEVEL_12)
    {
        lvl_idx = 1;
    }
    else if (level < IH264_LEVEL_13)
    {
        lvl_idx = 2;
    }
    else if (level < IH264_LEVEL_20)
    {
        lvl_idx = 3;
    }
    else if (level < IH264_LEVEL_21)
    {
        lvl_idx = 4;
    }
    else if (level < IH264_LEVEL_22)
    {
        lvl_idx = 5;
    }
    else if (level < IH264_LEVEL_30)
    {
        lvl_idx = 6;
    }
    else if (level < IH264_LEVEL_31)
    {
        lvl_idx = 7;
    }
    else if (level < IH264_LEVEL_32)
    {
        lvl_idx = 8;
    }
    else if (level < IH264_LEVEL_40)
    {
        lvl_idx = 9;
    }
    else if (level < IH264_LEVEL_41)
    {
        lvl_idx = 10;
    }
    else if (level < IH264_LEVEL_42)
    {
        lvl_idx = 11;
    }
    else if (level < IH264_LEVEL_50)
    {
        lvl_idx = 12;
    }
    else if (level < IH264_LEVEL_51)
    {
        lvl_idx = 13;
    }
    else
    {
        lvl_idx = 14;
    }

    return (lvl_idx);
}

/**
*******************************************************************************
*
* @brief returns maximum number of pictures allowed in dpb for a given level
*
* @par Description:
*  For given width, height and level, number of pictures allowed in decoder
*  picture buffer is computed as per Annex A.3.1
*
* @param[in] level
*  level of the bit-stream
*
* @param[in] pic_size
*  width * height
*
* @returns  Number of buffers in DPB
*
* @remarks
*  From annexure A.3.1 of H264 specification,
*  max_dec_frame_buffering <= MaxDpbSize, where MaxDpbSize is equal to
*  Min( 1024 * MaxDPB / ( PicWidthInMbs * FrameHeightInMbs * 384 ), 16 ) and
*  MaxDPB is given in Table A-1 in units of 1024 bytes. However the MaxDPB size
*  presented in the look up table gas_ih264_lvl_tbl is in units of 512
*  bytes. Hence the expression is modified accordingly.
*
*******************************************************************************
*/
WORD32 ih264e_get_dpb_size(WORD32 level, WORD32 pic_size)
{
    /* dpb size */
    WORD32 max_dpb_size_bytes = 0;

    /* dec frame buffering */
    WORD32 max_dpb_size_frames = 0;

    /* temp var */
    WORD32 i;

    /* determine max luma samples */
    for (i = 0; i < 16; i++)
        if (level == (WORD32)gas_ih264_lvl_tbl[i].u4_level_idc)
            max_dpb_size_bytes = gas_ih264_lvl_tbl[i].u4_max_dpb_size;

    /* from Annexure A.3.1 h264 specification */
    max_dpb_size_frames =
                    MIN( 1024 * max_dpb_size_bytes / ( pic_size * 3 ), MAX_DPB_SIZE );

    return max_dpb_size_frames;
}

/**
*******************************************************************************
*
* @brief
*  Used to get reference picture buffer size for a given level and
*  and padding used
*
* @par Description:
*  Used to get reference picture buffer size for a given level and padding used
*  Each picture is padded on all four sides
*
* @param[in] pic_size
*  Number of luma samples (Width * Height)
*
* @param[in] level
*  Level
*
* @param[in] horz_pad
*  Total padding used in horizontal direction
*
* @param[in] vert_pad
*  Total padding used in vertical direction
*
* @returns  Total picture buffer size
*
* @remarks
*
*
*******************************************************************************
*/
WORD32 ih264e_get_total_pic_buf_size(WORD32 pic_size,
                                     WORD32 level,
                                     WORD32 horz_pad,
                                     WORD32 vert_pad,
                                     WORD32 num_ref_frames,
                                     WORD32 num_reorder_frames)
{
    WORD32 size;
    WORD32 num_luma_samples;
    WORD32 lvl_idx;
    WORD32 max_wd, min_ht;
    WORD32 num_samples;
    WORD32 max_num_bufs;
    WORD32 pad = MAX(horz_pad, vert_pad);

    /*
     * If num_ref_frames and num_reorder_frmaes is specified
     * Use minimum value
     */
    max_num_bufs = (num_ref_frames + num_reorder_frames + MAX_CTXT_SETS);

    /* Get level index */
    lvl_idx = ih264e_get_lvl_idx(level);

    /* Maximum number of luma samples in a picture at given level */
    num_luma_samples = gai4_ih264_max_luma_pic_size[lvl_idx];
    num_luma_samples = MAX(num_luma_samples, pic_size);

    /* Account for chroma */
    num_samples = num_luma_samples * 3 / 2;

    /* Maximum width of luma samples in a picture at given level */
    max_wd = gai4_ih264_max_wd_ht[lvl_idx];

    /* Minimum height of luma samples in a picture at given level */
    min_ht = gai4_ih264_min_wd_ht[lvl_idx];

    /* Allocation is required for
     * (Wd + horz_pad) * (Ht + vert_pad) * (2 * max_dpb_size + 1)
     *
     * Above expanded as
     * ((Wd * Ht) + (horz_pad * vert_pad) + Wd * vert_pad + Ht * horz_pad) * (2 * max_dpb_size + 1)
     * (Wd * Ht) * (2 * max_dpb_size + 1) + ((horz_pad * vert_pad) + Wd * vert_pad + Ht * horz_pad) * (2 * max_dpb_size + 1)
     * Now  max_dpb_size increases with smaller Wd and Ht, but Wd * ht * max_dpb_size will still be lesser or equal to max_wd * max_ht * dpb_size
     *
     * In the above equation (Wd * Ht) * (2 * max_dpb_size + 1) is accounted by using num_samples * (2 * max_dpb_size + 1) below
     *
     * For the padded area use MAX(horz_pad, vert_pad) as pad
     * ((pad * pad) + pad * (Wd + Ht)) * (2 * max_dpb_size + 1) has to accounted from the above for padding
     *
     * Since Width and Height can change worst Wd + Ht is when One of the dimensions is max and other is min
     * So use max_wd and min_ht
     */

    /* Number of bytes in reference pictures */
    size = num_samples * max_num_bufs;

    /* Account for padding area */
    size += ((pad * pad) + pad * (max_wd + min_ht)) * 3 / 2 * max_num_bufs;

    return size;
}

/**
*******************************************************************************
*
* @brief Returns MV bank buffer size for a given number of luma samples
*
* @par Description:
*  For given number of luma samples  one MV bank size is computed.
*  Each MV bank includes pu_map and enc_pu_t for all the min PUs(4x4) in a picture
*
* @param[in] num_luma_samples
*  Max number of luma pixels in the frame
*
* @returns  Total MV Bank size
*
* @remarks
*
*******************************************************************************
*/
WORD32 ih264e_get_pic_mv_bank_size(WORD32 num_luma_samples)
{
    /* mv bank buffer size */
    WORD32 mv_bank_size = 0;

    /* number of sub mb partitions possible */
    WORD32 num_pu = num_luma_samples / (ENC_MIN_PU_SIZE * ENC_MIN_PU_SIZE);

    /* number of mbs */
    WORD32 num_mb = num_luma_samples / (MB_SIZE * MB_SIZE);

    /* Size for storing enc_pu_t start index each MB */
    /* One extra entry is needed to compute number of PUs in the last MB */
    mv_bank_size += num_mb * sizeof(WORD32);

    /* Size for pu_map */
    mv_bank_size += ALIGN4(num_pu);

    /* Size for storing enc_pu_t for each PU */
    mv_bank_size += ALIGN4(num_pu * sizeof(enc_pu_t));

    return mv_bank_size;
}

/**
*******************************************************************************
*
* @brief
*  Function to initialize ps_pic_buf structs add pic buffers to
*  buffer manager in case of non-shared mode
*
* @par Description:
*  Function to initialize ps_pic_buf structs add pic buffers to
*  buffer manager in case of non-shared mode
*  To be called once per stream or for every reset
*
* @param[in] ps_codec
*  Pointer to codec context
*
* @returns  error status
*
* @remarks
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_pic_buf_mgr_add_bufs(codec_t *ps_codec)
{
    /* error status */
    IH264E_ERROR_T ret = IH264E_SUCCESS;

    /* max ref buffer cnt */
    WORD32 max_num_bufs = ps_codec->i4_ref_buf_cnt;

    /* total size for pic buffers */
    WORD32 pic_buf_size_allocated = ps_codec->i4_total_pic_buf_size
                    - BUF_MGR_MAX_CNT * sizeof(pic_buf_t);

    /* temp var */
    UWORD8 *pu1_buf = (UWORD8 *) ps_codec->ps_pic_buf;
    pic_buf_t *ps_pic_buf = (pic_buf_t *) ps_codec->ps_pic_buf;
    WORD32 i;

    pu1_buf += BUF_MGR_MAX_CNT * sizeof(pic_buf_t);

    /* In case of non-shared mode, add picture buffers to buffer manager
     * In case of shared mode, buffers are added in the run-time
     */
    {
        WORD32 buf_ret;

        WORD32 luma_samples = (ps_codec->i4_rec_strd)
                        * (ps_codec->s_cfg.u4_ht + PAD_HT);

        WORD32 chroma_samples = luma_samples >> 1;

        /* Try and add as many buffers as possible for the memory that is allocated */
        /* If the number of buffers that can be added is less than max_num_bufs
         * return with an error */
        for (i = 0; i < max_num_bufs; i++)
        {
            pic_buf_size_allocated -= (luma_samples + chroma_samples);

            if (pic_buf_size_allocated < 0)
            {
                ps_codec->i4_error_code = IH264E_INSUFFICIENT_MEM_PICBUF;
                return IH264E_INSUFFICIENT_MEM_PICBUF;
            }

            ps_pic_buf->pu1_luma = pu1_buf + ps_codec->i4_rec_strd * PAD_TOP
                            + PAD_LEFT;
            pu1_buf += luma_samples;

            ps_pic_buf->pu1_chroma = pu1_buf
                            + ps_codec->i4_rec_strd * (PAD_TOP / 2)+ PAD_LEFT;
            pu1_buf += chroma_samples;

            buf_ret = ih264_buf_mgr_add((buf_mgr_t *) ps_codec->pv_ref_buf_mgr,
                                        ps_pic_buf, i);

            if (0 != buf_ret)
            {
                ps_codec->i4_error_code = IH264E_BUF_MGR_ERROR;
                return IH264E_BUF_MGR_ERROR;
            }
            pu1_buf += (HPEL_PLANES_CNT - 1) * (chroma_samples + luma_samples);
            ps_pic_buf++;
        }
    }

    return ret;
}

/**
*******************************************************************************
*
* @brief Function to add buffers to MV Bank buffer manager
*
* @par Description:
*  Function to add buffers to MV Bank buffer manager.  To be called once per
*  stream or for every reset
*
* @param[in] ps_codec
*  Pointer to codec context
*
* @returns  error status
*
* @remarks
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_mv_buf_mgr_add_bufs(codec_t *ps_codec)
{
    /* error status */
    IH264E_ERROR_T error_status = IH264E_SUCCESS;
    IH264_ERROR_T ret;

    /* max dpb size in frames */
    WORD32 max_dpb_size = 0;

    /* mv bank size for the entire dpb */
    WORD32 mv_bank_size_allocated = 0;

    /* mv bank size per pic */
    WORD32 pic_mv_bank_size = 0;

    /* mv buffer ptr */
    mv_buf_t *ps_mv_buf = NULL;

    /* num of luma samples */
    WORD32 num_luma_samples = ALIGN16(ps_codec->s_cfg.u4_wd)
                            * ALIGN16(ps_codec->s_cfg.u4_ht);

    /* number of mb's & frame partitions */
    WORD32 num_pu, num_mb;

    /* temp var */
    UWORD8 *pu1_buf = NULL;
    WORD32 i;

    /* Compute the number of MB Bank buffers needed */
    max_dpb_size = ps_codec->i4_ref_buf_cnt;

    /* allocate memory for mv buffer array */
    ps_codec->ps_mv_buf = ps_codec->pv_mv_bank_buf_base;
    pu1_buf = ps_codec->pv_mv_bank_buf_base;
    pu1_buf += BUF_MGR_MAX_CNT * sizeof(mv_buf_t);

    /********************************************************************/
    /* allocate memory for individual elements of mv buffer ptr         */
    /********************************************************************/
    mv_bank_size_allocated = ps_codec->i4_total_mv_bank_size
                    - (BUF_MGR_MAX_CNT * sizeof(mv_buf_t));

    /* compute MV bank size per picture */
    pic_mv_bank_size = ih264e_get_pic_mv_bank_size(num_luma_samples);

    num_pu = num_luma_samples / (ENC_MIN_PU_SIZE * ENC_MIN_PU_SIZE);
    num_mb = num_luma_samples / (MB_SIZE * MB_SIZE);
    i = 0;
    ps_mv_buf = ps_codec->pv_mv_bank_buf_base;

    while (i < max_dpb_size)
    {
        mv_bank_size_allocated -= pic_mv_bank_size;

        if (mv_bank_size_allocated < 0)
        {
            ps_codec->i4_error_code = IH264E_INSUFFICIENT_MEM_MVBANK;

            error_status = IH264E_INSUFFICIENT_MEM_MVBANK;

            return error_status;
        }

        ps_mv_buf->pu4_mb_pu_cnt = (UWORD32 *) pu1_buf;
        pu1_buf += num_mb * sizeof(WORD32);

        ps_mv_buf->pu1_pic_pu_map = pu1_buf;
        pu1_buf += ALIGN4(num_pu);

        ps_mv_buf->ps_pic_pu = (enc_pu_t *) (pu1_buf);
        pu1_buf += ALIGN4(num_pu * sizeof(enc_pu_t));

        ret = ih264_buf_mgr_add((buf_mgr_t *) ps_codec->pv_mv_buf_mgr,
                                ps_mv_buf, i);

        if (IH264_SUCCESS != ret)
        {
            ps_codec->i4_error_code = IH264E_BUF_MGR_ERROR;
            error_status = IH264E_BUF_MGR_ERROR;
            return error_status;
        }

        ps_mv_buf++;
        i++;
    }

    return error_status;
}

/**
*******************************************************************************
*
* @brief Function to initialize quant params structure
*
* @par Description:
*  The forward quantization modules depends on qp/6, qp mod 6, forward scale
*  matrix, forward threshold matrix, weight list. The inverse quantization
*  modules depends on qp/6, qp mod 6, inverse scale matrix, weight list.
*  These params are initialized in this function.
*
* @param[in] ps_proc
*  pointer to process context
*
* @param[in] qp
*  quantization parameter
*
* @returns none
*
* @remarks
*
*******************************************************************************
*/
void ih264e_init_quant_params(process_ctxt_t *ps_proc, int qp)
{
    /* quant params */
    quant_params_t *ps_qp_params;

    /* ptr to forward quant threshold matrix */
    const UWORD16 *pu2_thres_mat = NULL;

    /* ptr to forward scale matrix */
    const UWORD16 *pu2_scale_mat = gu2_quant_scale_matrix_4x4;

    /* ptr to inverse scale matrix */
    const UWORD16 *pu2_iscale_mat = gau2_ih264_iquant_scale_matrix_4x4;

    /* temp var */
    UWORD32 u4_qp[3], u4_qp_div6, u4_qp_mod6;
    COMPONENT_TYPE plane;
    WORD32 i;
    UWORD32 u4_satdq_t;
    const UWORD16 *pu2_smat;

    /********************************************************************/
    /* init quant params for all planes Y, U and V                      */
    /********************************************************************/
    /* luma qp */
    u4_qp[Y] = qp;

    /* chroma qp
     * TODO_LATER : just in case if the chroma planes use different qp's this
     * needs to be corrected accordingly.
     */
    u4_qp[U] = gu1_qpc_fqpi[qp];
    u4_qp[V] = gu1_qpc_fqpi[qp];

    plane = Y;
    while (plane <= V)
    {
        u4_qp_div6 = (u4_qp[plane] / 6);
        u4_qp_mod6 = (u4_qp[plane] % 6);

        ps_qp_params = ps_proc->ps_qp_params[plane];

        /* mb qp */
        ps_qp_params->u1_mb_qp = u4_qp[plane];

        /* mb qp / 6 */
        ps_qp_params->u1_qp_div = u4_qp_div6;

        /* mb qp % 6 */
        ps_qp_params->u1_qp_rem = u4_qp_mod6;

        /* QP bits */
        ps_qp_params->u1_qbits = QP_BITS_h264_4x4 + u4_qp_div6;

        /* forward scale matrix */
        ps_qp_params->pu2_scale_mat = pu2_scale_mat + (u4_qp_mod6 * 16);

        /* threshold matrix & weight for quantization */
        pu2_thres_mat = gu2_forward_quant_threshold_4x4 + (u4_qp_mod6 * 16);
        for (i = 0; i < 16; i++)
        {
            ps_qp_params->pu2_thres_mat[i] = pu2_thres_mat[i]
                            >> (8 - u4_qp_div6);
            ps_qp_params->pu2_weigh_mat[i] = 16;
        }

        /* qp dependent rounding constant */
        ps_qp_params->u4_dead_zone =
                        gu4_forward_quant_round_factor_4x4[u4_qp_div6];

        /* slice dependent rounding constant */
        if (ps_proc->i4_slice_type != ISLICE
                        && ps_proc->i4_slice_type != SISLICE)
        {
            ps_qp_params->u4_dead_zone >>= 1;
        }

        /* SATQD threshold for zero block prediction */
        if (ps_proc->ps_codec->s_cfg.u4_enable_satqd)
        {
            pu2_smat = ps_qp_params->pu2_scale_mat;

            u4_satdq_t = ((1 << (ps_qp_params->u1_qbits)) - ps_qp_params->u4_dead_zone);

            ps_qp_params->pu2_sad_thrsh[0] = u4_satdq_t / MAX(pu2_smat[3], pu2_smat[11]);
            ps_qp_params->pu2_sad_thrsh[1] = u4_satdq_t / MAX(pu2_smat[1], pu2_smat[9]);
            ps_qp_params->pu2_sad_thrsh[2] = u4_satdq_t / pu2_smat[15];
            ps_qp_params->pu2_sad_thrsh[3] = u4_satdq_t / pu2_smat[7];
            ps_qp_params->pu2_sad_thrsh[4] = u4_satdq_t / MAX(pu2_smat[12], pu2_smat[14]);
            ps_qp_params->pu2_sad_thrsh[5] = u4_satdq_t / MAX(pu2_smat[4], pu2_smat[6]);
            ps_qp_params->pu2_sad_thrsh[6] = u4_satdq_t / pu2_smat[13];
            ps_qp_params->pu2_sad_thrsh[7] = u4_satdq_t / pu2_smat[5];
            ps_qp_params->pu2_sad_thrsh[8] = u4_satdq_t / MAX(MAX3(pu2_smat[0], pu2_smat[2], pu2_smat[8]), pu2_smat[10]);
        }

        /* inverse scale matrix */
        ps_qp_params->pu2_iscale_mat = pu2_iscale_mat + (u4_qp_mod6 * 16);

        plane += 1;
    }
    return ;
}

/**
*******************************************************************************
*
* @brief
*  Initialize AIR mb frame Map
*
* @par Description:
*  Initialize AIR mb frame map
*  MB frame map indicates which frame an Mb should be coded as intra according to AIR
*
* @param[in] ps_codec
*  Pointer to codec context
*
* @returns  error_status
*
* @remarks
*
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_init_air_map(codec_t *ps_codec)
{
    /* intra refresh map */
    UWORD16 *pu2_intr_rfrsh_map = ps_codec->pu2_intr_rfrsh_map;

    /* air mode */
    IVE_AIR_MODE_T air_mode = ps_codec->s_cfg.e_air_mode;

    /* refresh period */
    UWORD32 air_period = ps_codec->s_cfg.u4_air_refresh_period;

    /* mb cnt */
    UWORD32 u4_mb_cnt = ps_codec->s_cfg.i4_wd_mbs * ps_codec->s_cfg.i4_ht_mbs;

    /* temp var */
    UWORD32 curr_mb, seed_rand = 1;

    switch (air_mode)
    {
        case IVE_AIR_MODE_CYCLIC:

            for (curr_mb = 0; curr_mb < u4_mb_cnt; curr_mb++)
            {
                pu2_intr_rfrsh_map[curr_mb] = curr_mb % air_period;
            }
            break;

        case IVE_AIR_MODE_RANDOM:

            for (curr_mb = 0; curr_mb < u4_mb_cnt; curr_mb++)
            {
                seed_rand = (seed_rand * 32719 + 3) % 32749;
                pu2_intr_rfrsh_map[curr_mb] = seed_rand % air_period;
            }
            break;

        default:

            break;
    }

    return IH264E_SUCCESS;
}

/**
*******************************************************************************
*
* @brief
*  Codec level initializations
*
* @par Description:
*  Initializes the codec with parameters that needs to be set before encoding
*  first frame
*
* @param[in] ps_codec
*  Pointer to codec context
*
* @param[in] ps_inp_buf
*  Pointer to input buffer context
*
* @returns  error_status
*
* @remarks
*
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_codec_init(codec_t *ps_codec)
{
    /********************************************************************
     *                     INITIALIZE CODEC CONTEXT                     *
     ********************************************************************/
    /* encoder presets */
    if (ps_codec->s_cfg.u4_enc_speed_preset != IVE_CONFIG)
    {
        if (ps_codec->s_cfg.u4_enc_speed_preset == IVE_SLOWEST)
        {/* high quality */
            /* enable diamond search */
            ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH;
            ps_codec->s_cfg.u4_enable_fast_sad = 0;

            /* disable intra 4x4 */
            ps_codec->s_cfg.u4_enable_intra_4x4 = 1;
            ps_codec->luma_energy_compaction[1] =
                            ih264e_code_luma_intra_macroblock_4x4_rdopt_on;

            /* sub pel off */
            ps_codec->s_cfg.u4_enable_hpel = 1;

            /* deblocking off */
            ps_codec->s_cfg.u4_disable_deblock_level = DISABLE_DEBLK_LEVEL_0;

            /* disabled intra inter gating in Inter slices */
            ps_codec->u4_inter_gate = 0;
        }
        else if (ps_codec->s_cfg.u4_enc_speed_preset == IVE_NORMAL)
        {/* normal */
            /* enable diamond search */
            ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH;
            ps_codec->s_cfg.u4_enable_fast_sad = 0;

            /* disable intra 4x4 */
            ps_codec->s_cfg.u4_enable_intra_4x4 = 1;

            /* sub pel off */
            ps_codec->s_cfg.u4_enable_hpel = 1;

            /* deblocking off */
            ps_codec->s_cfg.u4_disable_deblock_level = DISABLE_DEBLK_LEVEL_0;

            /* disabled intra inter gating in Inter slices */
            ps_codec->u4_inter_gate = 0;
        }
        else if (ps_codec->s_cfg.u4_enc_speed_preset == IVE_FAST)
         {/* normal */
             /* enable diamond search */
             ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH;
             ps_codec->s_cfg.u4_enable_fast_sad = 0;

             /* disable intra 4x4 */
             ps_codec->s_cfg.u4_enable_intra_4x4 = 0;

             /* sub pel off */
             ps_codec->s_cfg.u4_enable_hpel = 1;

             /* deblocking off */
             ps_codec->s_cfg.u4_disable_deblock_level = DISABLE_DEBLK_LEVEL_0;

             /* disabled intra inter gating in Inter slices */
             ps_codec->u4_inter_gate = 1;
         }
        else if (ps_codec->s_cfg.u4_enc_speed_preset == IVE_HIGH_SPEED)
        {/* fast */
            /* enable diamond search */
            ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH;
            ps_codec->s_cfg.u4_enable_fast_sad = 0;

            /* disable intra 4x4 */
            ps_codec->s_cfg.u4_enable_intra_4x4 = 0;

            /* sub pel off */
            ps_codec->s_cfg.u4_enable_hpel = 0;

            /* deblocking off */
            ps_codec->s_cfg.u4_disable_deblock_level = DISABLE_DEBLK_LEVEL_4;

            /* disabled intra inter gating in Inter slices */
            ps_codec->u4_inter_gate = 0;
        }
        else if (ps_codec->s_cfg.u4_enc_speed_preset == IVE_FASTEST)
        {/* fastest */
            /* enable diamond search */
            ps_codec->s_cfg.u4_me_speed_preset = DMND_SRCH;

            /* disable intra 4x4 */
            ps_codec->s_cfg.u4_enable_intra_4x4 = 0;

            /* sub pel off */
            ps_codec->s_cfg.u4_enable_hpel = 0;

            /* deblocking off */
            ps_codec->s_cfg.u4_disable_deblock_level = DISABLE_DEBLK_LEVEL_4;

            /* disabled intra inter gating in Inter slices */
            ps_codec->u4_inter_gate = 1;
        }
    }

    /*****************************************************************
     * Initialize AIR inside codec
     *****************************************************************/
    if (IVE_AIR_MODE_NONE != ps_codec->s_cfg.e_air_mode)
    {
        ih264e_init_air_map(ps_codec);

        ps_codec->i4_air_pic_cnt = -1;
    }

    /****************************************************/
    /*           INITIALIZE RATE CONTROL                */
    /****************************************************/
    {
        /* init qp */
        UWORD8 au1_init_qp[MAX_PIC_TYPE];

        /* min max qp */
        UWORD8 au1_min_max_qp[2 * MAX_PIC_TYPE];

        /* init i,p,b qp */
        au1_init_qp[0] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_i_qp];
        au1_init_qp[1] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_p_qp];
        au1_init_qp[2] = gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_b_qp];

        /* init min max qp */
        au1_min_max_qp[2 * I_PIC] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_i_qp_min];
        au1_min_max_qp[2 * I_PIC + 1] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_i_qp_max];

        au1_min_max_qp[2 * P_PIC] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_p_qp_min];
        au1_min_max_qp[2 * P_PIC + 1] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_p_qp_max];

        au1_min_max_qp[2 * B_PIC] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_b_qp_min];
        au1_min_max_qp[2 * B_PIC + 1] =
                        gau1_h264_to_mpeg2_qmap[ps_codec->s_cfg.u4_b_qp_max];

        /* get rc mode */
        switch (ps_codec->s_cfg.e_rc_mode)
        {
            case IVE_RC_STORAGE:
                ps_codec->s_rate_control.e_rc_type = VBR_STORAGE;
                break;
            case IVE_RC_CBR_NON_LOW_DELAY:
                ps_codec->s_rate_control.e_rc_type = CBR_NLDRC;
                break;
            case IVE_RC_CBR_LOW_DELAY:
                ps_codec->s_rate_control.e_rc_type = CBR_LDRC;
                break;
            case IVE_RC_NONE:
                ps_codec->s_rate_control.e_rc_type = CONST_QP;
                break;
            default:
                break;
        }

        /* init rate control */
        ih264e_rc_init(ps_codec->s_rate_control.pps_rate_control_api,
                       ps_codec->s_rate_control.pps_frame_time,
                       ps_codec->s_rate_control.pps_time_stamp,
                       ps_codec->s_rate_control.pps_pd_frm_rate,
                       ps_codec->s_cfg.u4_max_framerate,
                       ps_codec->s_cfg.u4_src_frame_rate,
                       ps_codec->s_cfg.u4_tgt_frame_rate,
                       ps_codec->s_rate_control.e_rc_type,
                       ps_codec->s_cfg.u4_target_bitrate,
                       ps_codec->s_cfg.u4_max_bitrate,
                       ps_codec->s_cfg.u4_vbv_buffer_delay,
                       ps_codec->s_cfg.u4_i_frm_interval,
                       ps_codec->s_cfg.u4_num_bframes + 1, au1_init_qp,
                       ps_codec->s_cfg.u4_num_bframes + 2 , au1_min_max_qp,
                       MAX(ps_codec->s_cfg.u4_max_level,
                               (UWORD32)ih264e_get_min_level(ps_codec->s_cfg.u4_max_wd, ps_codec->s_cfg.u4_max_ht)));
    }

    /* recon stride */
    ps_codec->i4_rec_strd = ALIGN16(ps_codec->s_cfg.u4_max_wd) + PAD_WD;

    /* max ref and reorder cnt */
    ps_codec->i4_ref_buf_cnt = ps_codec->s_cfg.u4_max_ref_cnt
                    + ps_codec->s_cfg.u4_max_reorder_cnt;
    ps_codec->i4_ref_buf_cnt += MAX_CTXT_SETS;

    DEBUG_HISTOGRAM_INIT();


    /* Init dependecy vars */
    ps_codec->i4_last_inp_buff_received = 0;

    /* At codec start no IDR is pending */
    ps_codec->i4_pending_idr_flag = 0;

    return IH264E_SUCCESS;
}

/**
*******************************************************************************
*
* @brief
*  Picture level initializations
*
* @par Description:
*  Before beginning to encode the frame, the current function initializes all
*  the ctxts (proc, entropy, me, ...) basing on the input configured params.
*  It locates space for storing recon in the encoder picture buffer set, fetches
*  reference frame from encoder picture buffer set. Calls RC pre-enc to get
*  qp and pic type for the current frame. Queues proc jobs so that
*  the other threads can begin encoding. In brief, this function sets up the
*  tone for the entire encoder.
*
* @param[in] ps_codec
*  Pointer to codec context
*
* @param[in] ps_inp_buf
*  Pointer to input buffer context
*
* @returns  error_status
*
* @remarks
*
*
*******************************************************************************
*/
IH264E_ERROR_T ih264e_pic_init(codec_t *ps_codec, inp_buf_t *ps_inp_buf)
{
    /* error status */
    IH264E_ERROR_T error_status = IH264E_SUCCESS;
    IH264_ERROR_T ret = IH264_SUCCESS;

    /* mv buff bank */
    mv_buf_t *ps_mv_buf = NULL;
    WORD32 cur_mv_bank_buf_id;

    /* recon buffer set */
    pic_buf_t *ps_cur_pic;
    WORD32 cur_pic_buf_id;
    UWORD8 *pu1_cur_pic_luma, *pu1_cur_pic_chroma;

    /* ref buffer set */
    pic_buf_t *aps_ref_pic[MAX_REF_PIC_CNT] = {NULL, NULL};
    mv_buf_t *aps_mv_buf[MAX_REF_PIC_CNT] = {NULL, NULL};
    WORD32 ref_set_id;

    /* pic time stamp */
    UWORD32 u4_timestamp_high = ps_inp_buf->u4_timestamp_high;
    UWORD32 u4_timestamp_low = ps_inp_buf->u4_timestamp_low;

    /* indices to access curr/prev frame info */
    WORD32 ctxt_sel = ps_codec->i4_encode_api_call_cnt % MAX_CTXT_SETS;

    /* curr pic type */
    PIC_TYPE_T *pic_type = &ps_codec->pic_type;

    /* Diamond search Iteration Max Cnt */
    UWORD32 u4_num_layers =
                    (ps_codec->s_cfg.u4_enc_speed_preset == IVE_FASTEST) ?
                                    (NUM_LAYERS >> 2) : NUM_LAYERS;

    /* enable fast sad */
    UWORD32 u4_enable_fast_sad = ps_codec->s_cfg.u4_enable_fast_sad;

    /********************************************************************/
    /*                     INITIALIZE CODEC CONTEXT                     */
    /********************************************************************/
    /* slice_type */
    if ((PIC_I == *pic_type) || (PIC_IDR == *pic_type))
    {
        ps_codec->i4_slice_type = ISLICE;
    }
    else if (PIC_P == *pic_type)
    {
        ps_codec->i4_slice_type = PSLICE;
    }
    else if(PIC_B == *pic_type)
    {
        ps_codec->i4_slice_type = BSLICE;
    }


    /***************************************************************************
     * Set up variables for sending frame number, poc and reference
     *   a) Set up alt ref too
     **************************************************************************/

    /* Check and set if the current frame is reference or not */
    ps_codec->u4_is_curr_frm_ref = 0;

    /* This frame is reference if its not a B pic, pending approval from alt ref */
    ps_codec->u4_is_curr_frm_ref = (*pic_type != PIC_B);

    /* In case if its a P pic, we will decide according to alt ref also */
    if (ps_codec->s_cfg.u4_enable_alt_ref && (*pic_type == PIC_P)
                    && (ps_codec->i4_pic_cnt
                                    % (ps_codec->s_cfg.u4_enable_alt_ref + 1)))
    {
        ps_codec->u4_is_curr_frm_ref = 0;
    }

    /*
     * Override everything in case of IDR
     * Note that in case of IDR, at this point ps_codec->u4_is_curr_frm_ref must
     * be 1
     */

    /* is this an IDR pic */
    ps_codec->u4_is_idr = 0;

    if (PIC_IDR == *pic_type)
    {
        /* set idr flag */
        ps_codec->u4_is_idr = 1;

        /* reset frame num */
        ps_codec->i4_frame_num = 0;

        /* idr_pic_id */
        ps_codec->i4_idr_pic_id++;
    }

    /***************************************************************************
     * Set up Deblock
     **************************************************************************/

    /* set deblock disable flags based on disable deblock level */
    ps_codec->i4_disable_deblk_pic = 1;

    if (ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_0)
    {
        /* enable deblocking */
        ps_codec->i4_disable_deblk_pic = 0;
    }
    else if (ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_2)
    {
        /* enable deblocking after a period of frames */
        if (ps_codec->i4_disable_deblk_pic_cnt == DISABLE_DEBLOCK_INTERVAL
                        || ps_codec->i4_slice_type == ISLICE)
        {
            ps_codec->i4_disable_deblk_pic = 0;
        }
    }
    else if (ps_codec->s_cfg.u4_disable_deblock_level == DISABLE_DEBLK_LEVEL_3)
    {
        if (ps_codec->i4_slice_type == ISLICE)
        {
            ps_codec->i4_disable_deblk_pic = 0;
        }
    }

    if (ps_codec->i4_disable_deblk_pic)
    {
        ps_codec->i4_disable_deblk_pic_cnt++;
    }
    else
    {
        ps_codec->i4_disable_deblk_pic_cnt = 0;
    }

    /* In slice mode - lets not deblk mb edges that lie along slice boundaries */
    if (ps_codec->i4_disable_deblk_pic == 0)
    {
        if (ps_codec->s_cfg.e_slice_mode != IVE_SLICE_MODE_NONE)
        {
            ps_codec->i4_disable_deblk_pic = 2;
        }
    }

    /* error status */
    ps_codec->i4_error_code = IH264E_SUCCESS;

    /* populate header */
    if (ps_codec->i4_gen_header)
    {
        /* sps */
        sps_t *ps_sps = NULL;

        /* pps */
        pps_t *ps_pps = NULL;

        /*ps_codec->i4_pps_id ++;*/
        ps_codec->i4_pps_id %= MAX_PPS_CNT;

        /*ps_codec->i4_sps_id ++;*/
        ps_codec->i4_sps_id %= MAX_SPS_CNT;

        /* populate sps header */
        ps_sps = ps_codec->ps_sps_base + ps_codec->i4_sps_id;
        ih264e_populate_sps(ps_codec, ps_sps);

        /* populate pps header */
        ps_pps = ps_codec->ps_pps_base + ps_codec->i4_pps_id;
        ih264e_populate_pps(ps_codec, ps_pps);
    }

    /***************************************************************************
     *  Reference and MV bank Buffer Manager
     *  Here we will
     *      1) Find the correct ref pics for the current frame
     *      2) Free the ref pic that is not going to be used anywhere
     *      3) Find a free buff from the list and assign it as the recon of
     *         current frame
     *
     *  1) Finding correct ref pic
     *      All pics needed for future are arranged in a picture list called
     *      ps_codec->as_ref_set. Each picture in this will have a pic buffer and
     *      MV buffer that is marked appropriately as BUF_MGR_REF, BUF_MGR_IO or
     *      BUF_MGR_CODEC. Also the pic_cnt and poc will also be present.
     *      Hence to find the ref pic we will loop through the list and find
     *      2 pictures with maximum i4_pic_cnt .
     *
     *      note that i4_pic_cnt == -1 is used to filter uninit ref pics.
     *      Now since we only have max two ref pics, we will always find max 2
     *      ref pics.

     *
     *  2) 3) Self explanatory
     ***************************************************************************/
    {
        /* Search for buffs with maximum pic cnt */

        WORD32 max_pic_cnt[] = { -1, -1 };

        mv_buf_t *ps_mv_buf_to_free[] = { NULL, NULL };

        /* temp var */
        WORD32 i, buf_status;

        for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
        {
            if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
                continue;

            buf_status = ih264_buf_mgr_get_status(
                            ps_codec->pv_ref_buf_mgr,
                            ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);

            /* Ideally we should look for buffer status of MV BUFF also. But since
             * the correponding MV buffs also will be at the same state. It dosent
             * matter as of now. But the check will make the logic better */
            if ((max_pic_cnt[0] < ps_codec->as_ref_set[i].i4_pic_cnt)
                            && (buf_status & BUF_MGR_REF))
            {
                if (max_pic_cnt[1] < ps_codec->as_ref_set[i].i4_pic_cnt)
                {
                    max_pic_cnt[0] = max_pic_cnt[1];
                    aps_ref_pic[0] = aps_ref_pic[1];
                    aps_mv_buf[0] = aps_mv_buf[1];

                    ps_mv_buf_to_free[0] = ps_mv_buf_to_free[1];

                    max_pic_cnt[1] = ps_codec->as_ref_set[i].i4_pic_cnt;
                    aps_ref_pic[1] = ps_codec->as_ref_set[i].ps_pic_buf;
                    aps_mv_buf[1] = ps_codec->as_ref_set[i].ps_mv_buf;
                    ps_mv_buf_to_free[1] = ps_codec->as_ref_set[i].ps_mv_buf;

                }
                else
                {
                    max_pic_cnt[0] = ps_codec->as_ref_set[i].i4_pic_cnt;
                    aps_ref_pic[0] = ps_codec->as_ref_set[i].ps_pic_buf;
                    aps_mv_buf[0] = ps_codec->as_ref_set[i].ps_mv_buf;
                    ps_mv_buf_to_free[0] = ps_codec->as_ref_set[i].ps_mv_buf;
                }
            }
        }

        /*
         * Now if the current picture is I or P, we discard the back ref pic and
         * assign forward ref as backward ref
         */
        if (*pic_type != PIC_B)
        {
            if (ps_mv_buf_to_free[0])
            {
                /* release this frame from reference list */
                ih264_buf_mgr_release(ps_codec->pv_mv_buf_mgr,
                                      ps_mv_buf_to_free[0]->i4_buf_id,
                                      BUF_MGR_REF);

                ih264_buf_mgr_release(ps_codec->pv_ref_buf_mgr,
                                      aps_ref_pic[0]->i4_buf_id, BUF_MGR_REF);
            }

            max_pic_cnt[0] = max_pic_cnt[1];
            aps_ref_pic[0] = aps_ref_pic[1];
            aps_mv_buf[0] = aps_mv_buf[1];

            /* Dummy */
            max_pic_cnt[1] = -1;
        }

        /*
         * Mark all reference pic with unused buffers to be free
         * We need this step since each one, ie ref, recon io etc only unset their
         * respective flags. Hence we need to combine togather and mark the ref set
         * accordingly
         */
        ref_set_id = -1;
        for (i = 0; i < ps_codec->i4_ref_buf_cnt; i++)
        {
            if (ps_codec->as_ref_set[i].i4_pic_cnt == -1)
            {
                ref_set_id = i;
                continue;
            }

            buf_status = ih264_buf_mgr_get_status(
                            ps_codec->pv_ref_buf_mgr,
                            ps_codec->as_ref_set[i].ps_pic_buf->i4_buf_id);

            if ((buf_status & (BUF_MGR_REF | BUF_MGR_CODEC | BUF_MGR_IO)) == 0)
            {
                ps_codec->as_ref_set[i].i4_pic_cnt = -1;
                ps_codec->as_ref_set[i].i4_poc = 32768;

                ref_set_id = i;
            }
        }
        /* An asssert failure here means we donot have any free buffs */
        ASSERT(ref_set_id >= 0);
    }

    {
        /*****************************************************************/
        /* Get free MV Bank to hold current picture's motion vector data */
        /* If there are no free buffers then return with an error code.  */
        /* If the buffer is to be freed by another thread, change the    */
        /* following to call thread yield and wait for buffer to be freed*/
        /*****************************************************************/
        ps_mv_buf = (mv_buf_t *) ih264_buf_mgr_get_next_free(
                        (buf_mgr_t *) ps_codec->pv_mv_buf_mgr,
                        &cur_mv_bank_buf_id);

        if (NULL == ps_mv_buf)
        {
            ps_codec->i4_error_code = IH264E_NO_FREE_MVBANK;
            return IH264E_NO_FREE_MVBANK;
        }

        /* mark the buffer as needed for reference if the curr pic is available for ref */
        if (ps_codec->u4_is_curr_frm_ref)
        {
            ih264_buf_mgr_set_status(ps_codec->pv_mv_buf_mgr,
                                     cur_mv_bank_buf_id, BUF_MGR_REF);
        }

        /* Set current ABS poc to ps_mv_buf, so that while freeing a reference buffer
         * corresponding mv buffer can be found by looping through ps_codec->ps_mv_buf array
         * and getting a buffer id to free
         */
        ps_mv_buf->i4_abs_poc = ps_codec->i4_abs_pic_order_cnt;
        ps_mv_buf->i4_buf_id = cur_mv_bank_buf_id;
    }

    {
        /*****************************************************************/
        /* Get free pic buf to hold current picture's recon data         */
        /* If there are no free buffers then return with an error code.  */
        /* If the buffer is to be freed by another thread, change the    */
        /* following to call thread yield and wait for buffer to be freed*/
        /*****************************************************************/
        ps_cur_pic = (pic_buf_t *) ih264_buf_mgr_get_next_free(
                        (buf_mgr_t *) ps_codec->pv_ref_buf_mgr,
                        &cur_pic_buf_id);

        if (NULL == ps_cur_pic)
        {
            ps_codec->i4_error_code = IH264E_NO_FREE_PICBUF;
            return IH264E_NO_FREE_PICBUF;
        }

        /* mark the buffer as needed for reference if the curr pic is available for ref */
        if (ps_codec->u4_is_curr_frm_ref)
        {
            ih264_buf_mgr_set_status(ps_codec->pv_ref_buf_mgr, cur_pic_buf_id,
                                     BUF_MGR_REF);
        }

        /* Mark the current buffer as needed for IO if recon is enabled */
        if (1 == ps_codec->s_cfg.u4_enable_recon)
        {
            ih264_buf_mgr_set_status(ps_codec->pv_ref_buf_mgr, cur_pic_buf_id,
                                     BUF_MGR_IO);
        }

        /* Associate input timestamp with current buffer */
        ps_cur_pic->u4_timestamp_high = ps_inp_buf->u4_timestamp_high;
        ps_cur_pic->u4_timestamp_low = ps_inp_buf->u4_timestamp_low;

        ps_cur_pic->i4_abs_poc = ps_codec->i4_poc;
        ps_cur_pic->i4_poc_lsb = ps_codec->i4_pic_order_cnt_lsb;

        ps_cur_pic->i4_buf_id = cur_pic_buf_id;

        pu1_cur_pic_luma = ps_cur_pic->pu1_luma;
        pu1_cur_pic_chroma = ps_cur_pic->pu1_chroma;
    }

    /*
     * Add the current picture to ref list independent of the fact that it is used
     * as reference or not. This is because, now recon is not in sync with output
     * hence we may need the current recon after some delay. By adding it to ref list
     * we can retrieve the recon any time we want. The information that it is used
     * for ref can still be found by checking the buffer status of pic buf.
     */
    {
        ps_codec->as_ref_set[ref_set_id].i4_pic_cnt = ps_codec->i4_pic_cnt;
        ps_codec->as_ref_set[ref_set_id].i4_poc = ps_codec->i4_poc;
        ps_codec->as_ref_set[ref_set_id].ps_mv_buf = ps_mv_buf;
        ps_codec->as_ref_set[ref_set_id].ps_pic_buf = ps_cur_pic;
    }

    /********************************************************************/
    /*                     INITIALIZE PROCESS CONTEXT                   */
    /********************************************************************/
    {
        /* temp var */
        WORD32 i, j = 0;

        /* curr proc ctxt */
        process_ctxt_t *ps_proc = NULL;

        j = ctxt_sel * MAX_PROCESS_THREADS;

        /* begin init */
        for (i = j; i < (j + MAX_PROCESS_THREADS); i++)
        {
            ps_proc = &ps_codec->as_process[i];

            /* luma src buffer */
            if (ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_422ILE)
            {
                ps_proc->pu1_src_buf_luma_base = ps_codec->pu1_y_csc_buf_base;
            }
            else
            {
                ps_proc->pu1_src_buf_luma_base =
                                ps_inp_buf->s_raw_buf.apv_bufs[0];
            }

            /* chroma src buffer */
            if (ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_422ILE
                            || ps_codec->s_cfg.e_inp_color_fmt == IV_YUV_420P)
            {
                ps_proc->pu1_src_buf_chroma_base =
                                ps_codec->pu1_uv_csc_buf_base;
            }
            else
            {
                ps_proc->pu1_src_buf_chroma_base =
                                ps_inp_buf->s_raw_buf.apv_bufs[1];
            }

            /* luma rec buffer */
            ps_proc->pu1_rec_buf_luma_base = pu1_cur_pic_luma;

            /* chroma rec buffer */
            ps_proc->pu1_rec_buf_chroma_base = pu1_cur_pic_chroma;

            /* rec stride */
            ps_proc->i4_rec_strd = ps_codec->i4_rec_strd;

            /* frame num */
            ps_proc->i4_frame_num = ps_codec->i4_frame_num;

            /* is idr */
            ps_proc->u4_is_idr = ps_codec->u4_is_idr;

            /* idr pic id */
            ps_proc->u4_idr_pic_id = ps_codec->i4_idr_pic_id;

            /* slice_type */
            ps_proc->i4_slice_type = ps_codec->i4_slice_type;

            /* Input width in mbs */
            ps_proc->i4_wd_mbs = ps_codec->s_cfg.i4_wd_mbs;

            /* Input height in mbs */
            ps_proc->i4_ht_mbs = ps_codec->s_cfg.i4_ht_mbs;

            /* Half x plane offset from pic buf */
            ps_proc->u4_half_x_offset = 0;

            /* Half y plane offset from half x plane */
            ps_proc->u4_half_y_offset = 0;

            /* Half x plane offset from half y plane */
            ps_proc->u4_half_xy_offset = 0;

            /* top row syntax elements */
            ps_proc->ps_top_row_mb_syntax_ele =
                            ps_proc->ps_top_row_mb_syntax_ele_base;

            ps_proc->pu1_top_mb_intra_modes =
                            ps_proc->pu1_top_mb_intra_modes_base;

            ps_proc->ps_top_row_pu = ps_proc->ps_top_row_pu_base;

            /* initialize quant params */
            ps_proc->u4_frame_qp = ps_codec->u4_frame_qp;
            ps_proc->u4_mb_qp = ps_codec->u4_frame_qp;
            ih264e_init_quant_params(ps_proc, ps_proc->u4_frame_qp);

            /* previous mb qp*/
            ps_proc->u4_mb_qp_prev = ps_proc->u4_frame_qp;

            /* Reset frame info */
            memset(&ps_proc->s_frame_info, 0, sizeof(frame_info_t));

            /* initialize proc, deblk and ME map */
            if (i == j)
            {
                /* row '-1' */
                memset(ps_proc->pu1_proc_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs);
                /* row 0 to ht in mbs */
                memset(ps_proc->pu1_proc_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);

                /* row '-1' */
                memset(ps_proc->pu1_deblk_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs);
                /* row 0 to ht in mbs */
                memset(ps_proc->pu1_deblk_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);

                /* row '-1' */
                memset(ps_proc->pu1_me_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs);
                /* row 0 to ht in mbs */
                memset(ps_proc->pu1_me_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);

                /* at the start of air refresh period, reset intra coded map */
                if (IVE_AIR_MODE_NONE != ps_codec->s_cfg.e_air_mode)
                {
                    ps_codec->i4_air_pic_cnt = (ps_codec->i4_air_pic_cnt + 1)
                                    % ps_codec->s_cfg.u4_air_refresh_period;

                    if (!ps_codec->i4_air_pic_cnt)
                    {
                        memset(ps_proc->pu1_is_intra_coded, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);
                    }
                }
            }

            /* deblock level */
            ps_proc->u4_disable_deblock_level = ps_codec->i4_disable_deblk_pic;

            /* slice index map */
            /* no slice */
            if (ps_codec->s_cfg.e_slice_mode == IVE_SLICE_MODE_NONE)
            {
                memset(ps_proc->pu1_slice_idx, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);
            }
            /* generate slices for every 'n' rows, 'n' is given through slice param */
            else if (ps_codec->s_cfg.e_slice_mode == IVE_SLICE_MODE_BLOCKS)
            {
                /* slice idx map */
                UWORD8 *pu1_slice_idx = ps_proc->pu1_slice_idx;

                /* temp var */
                WORD32 i4_mb_y = 0, slice_idx = 0, cnt;

                while (i4_mb_y < ps_proc->i4_ht_mbs)
                {
                    if (i4_mb_y +(WORD32)ps_codec->s_cfg.u4_slice_param < ps_proc->i4_ht_mbs)
                    {
                        cnt = ps_codec->s_cfg.u4_slice_param * ps_proc->i4_wd_mbs;
                        i4_mb_y += ps_codec->s_cfg.u4_slice_param;
                    }
                    else
                    {
                        cnt = (ps_proc->i4_ht_mbs - i4_mb_y) * ps_proc->i4_wd_mbs;
                        i4_mb_y += (ps_proc->i4_ht_mbs - i4_mb_y);
                    }
                    memset(pu1_slice_idx, slice_idx, cnt);
                    slice_idx++;
                    pu1_slice_idx += cnt;
                }
            }

            /* Current MV Bank's buffer ID */
            ps_proc->i4_cur_mv_bank_buf_id = cur_mv_bank_buf_id;

            /* Pointer to current picture buffer structure */
            ps_proc->ps_cur_pic = ps_cur_pic;

            /* Pointer to current pictures mv buffers */
            ps_proc->ps_cur_mv_buf = ps_mv_buf;

            /*
             * pointer to ref picture
             * 0    : Temporal back reference
             * 1    : Temporal forward reference
             */
            ps_proc->aps_ref_pic[PRED_L0] = aps_ref_pic[PRED_L0];
            ps_proc->aps_ref_pic[PRED_L1] = aps_ref_pic[PRED_L1];
            if (ps_codec->pic_type == PIC_B)
            {
                ps_proc->aps_mv_buf[PRED_L0] = aps_mv_buf[PRED_L0];
                ps_proc->aps_mv_buf[PRED_L1] = aps_mv_buf[PRED_L1];
            }
            else
            {
                /*
                 * Else is dummy since for non B pic we does not need this
                 * But an assignment here will help in not having a segfault
                 * when we calcualte colpic in P slices
                 */
                ps_proc->aps_mv_buf[PRED_L0] = ps_mv_buf;
                ps_proc->aps_mv_buf[PRED_L1] = ps_mv_buf;
            }

            if ((*pic_type != PIC_IDR) && (*pic_type != PIC_I))
            {
                /* temporal back an forward  ref pointer luma and chroma */
                ps_proc->apu1_ref_buf_luma_base[PRED_L0] = aps_ref_pic[PRED_L0]->pu1_luma;
                ps_proc->apu1_ref_buf_chroma_base[PRED_L0] = aps_ref_pic[PRED_L0]->pu1_chroma;

                ps_proc->apu1_ref_buf_luma_base[PRED_L1] = aps_ref_pic[PRED_L1]->pu1_luma;
                ps_proc->apu1_ref_buf_chroma_base[PRED_L1] = aps_ref_pic[PRED_L1]->pu1_chroma;
            }

            /* Structure for current input buffer */
            ps_proc->s_inp_buf = *ps_inp_buf;

            /* Number of encode frame API calls made */
            ps_proc->i4_encode_api_call_cnt = ps_codec->i4_encode_api_call_cnt;

            /* Current Picture count */
            ps_proc->i4_pic_cnt = ps_codec->i4_pic_cnt;

            /* error status */
            ps_proc->i4_error_code = 0;

            /********************************************************************/
            /*                     INITIALIZE ENTROPY CONTEXT                   */
            /********************************************************************/
            {
                entropy_ctxt_t *ps_entropy = &ps_proc->s_entropy;

                /* start of frame */
                ps_entropy->i4_sof = 0;

                /* end of frame */
                ps_entropy->i4_eof = 0;

                /* generate header */
                ps_entropy->i4_gen_header = ps_codec->i4_gen_header;

                /* sps ref_set_id */
                ps_entropy->u4_sps_id = ps_codec->i4_sps_id;

                /* sps base */
                ps_entropy->ps_sps_base = ps_codec->ps_sps_base;

                /* sps id */
                ps_entropy->u4_pps_id = ps_codec->i4_pps_id;

                /* sps base */
                ps_entropy->ps_pps_base = ps_codec->ps_pps_base;

                /* slice map */
                ps_entropy->pu1_slice_idx = ps_proc->pu1_slice_idx;

                /* slice hdr base */
                ps_entropy->ps_slice_hdr_base = ps_proc->ps_slice_hdr_base;

                /* Abs poc */
                ps_entropy->i4_abs_pic_order_cnt = ps_proc->ps_codec->i4_poc;

                /* initialize entropy map */
                if (i == j)
                {
                    /* row '-1' */
                    memset(ps_entropy->pu1_entropy_map - ps_proc->i4_wd_mbs, 1, ps_proc->i4_wd_mbs);
                    /* row 0 to ht in mbs */
                    memset(ps_entropy->pu1_entropy_map, 0, ps_proc->i4_wd_mbs * ps_proc->i4_ht_mbs);

                    /* intialize cabac tables */
                    ih264e_init_cabac_table(ps_entropy);
                }

                /* wd in mbs */
                ps_entropy->i4_wd_mbs = ps_proc->i4_wd_mbs;

                /* ht in mbs */
                ps_entropy->i4_ht_mbs = ps_proc->i4_ht_mbs;

                /* transform_8x8_mode_flag */
                ps_entropy->i1_transform_8x8_mode_flag = 0;

                /* entropy_coding_mode_flag */
                ps_entropy->u1_entropy_coding_mode_flag =
                                ps_codec->s_cfg.u4_entropy_coding_mode;

                /* error code */
                ps_entropy->i4_error_code = IH264E_SUCCESS;

                /* mb skip run */
                *(ps_proc->s_entropy.pi4_mb_skip_run) = 0;

                /* last frame to encode */
                ps_proc->s_entropy.u4_is_last = ps_inp_buf->u4_is_last;

                /* Current Picture count */
                ps_proc->s_entropy.i4_pic_cnt = ps_codec->i4_pic_cnt;

                /* time stamps */
                ps_entropy->u4_timestamp_low = u4_timestamp_low;
                ps_entropy->u4_timestamp_high = u4_timestamp_high;

                /* init frame statistics */
                ps_entropy->u4_header_bits[MB_TYPE_INTRA] = 0;
                ps_entropy->u4_header_bits[MB_TYPE_INTER] = 0;
                ps_entropy->u4_residue_bits[MB_TYPE_INTRA] = 0;
                ps_entropy->u4_residue_bits[MB_TYPE_INTER] = 0;
            }

            /********************************************************************/
            /*                     INITIALIZE DEBLOCK CONTEXT                   */
            /********************************************************************/
            {
                /* deblk ctxt */
                deblk_ctxt_t *ps_deblk = &ps_proc->s_deblk_ctxt;

                /* slice idx map */
                ps_deblk->pu1_slice_idx = ps_proc->pu1_slice_idx;
            }

            /********************************************************************/
            /*                     INITIALIZE ME CONTEXT                        */
            /********************************************************************/
            {
                /* me ctxt */
                me_ctxt_t *ps_me_ctxt = &ps_proc->s_me_ctxt;

                /* srch range x */
                ps_me_ctxt->ai2_srch_boundaries[0] =
                                ps_codec->s_cfg.u4_srch_rng_x;

                /* srch range y */
                ps_me_ctxt->ai2_srch_boundaries[1] =
                                ps_codec->s_cfg.u4_srch_rng_y;

                /* rec stride */
                ps_me_ctxt->i4_rec_strd = ps_codec->i4_rec_strd;

                /* Half x plane offset from pic buf */
                ps_me_ctxt->u4_half_x_offset = ps_proc->u4_half_x_offset;

                /* Half y plane offset from half x plane */
                ps_me_ctxt->u4_half_y_offset = ps_proc->u4_half_y_offset;

                /* Half x plane offset from half y plane */
                ps_me_ctxt->u4_half_xy_offset = ps_proc->u4_half_xy_offset;

                /* enable fast sad */
                ps_me_ctxt->u4_enable_fast_sad = u4_enable_fast_sad;

                /* half pel */
                ps_me_ctxt->u4_enable_hpel = ps_codec->s_cfg.u4_enable_hpel;

                /* Diamond search Iteration Max Cnt */
                ps_me_ctxt->u4_num_layers = u4_num_layers;

                /* me speed preset */
                ps_me_ctxt->u4_me_speed_preset =
                                ps_codec->s_cfg.u4_me_speed_preset;

                /* qp */
                ps_me_ctxt->u1_mb_qp = ps_codec->u4_frame_qp;

                if ((i == j) && (0 == ps_codec->i4_poc))
                {
                    /* init mv bits tables */
                    ih264e_init_mv_bits(ps_me_ctxt);
                }
            }

            ps_proc->ps_ngbr_avbl = &(ps_proc->s_ngbr_avbl);

        }

        /* reset encoder header */
        ps_codec->i4_gen_header = 0;
    }

    /********************************************************************/
    /*                       ADD JOBS TO THE QUEUE                      */
    /********************************************************************/
    {
        /* job structures */
        job_t s_job;

        /* temp var */
        WORD32 i;

        /* job class */
        s_job.i4_cmd = CMD_PROCESS;

        /* number of mbs to be processed in the current job */
        s_job.i2_mb_cnt = ps_codec->s_cfg.i4_wd_mbs;

        /* job start index x */
        s_job.i2_mb_x = 0;

        /* proc base idx */
        s_job.i2_proc_base_idx = ctxt_sel ? (MAX_PROCESS_CTXT / 2) : 0;

        for (i = 0; i < (WORD32)ps_codec->s_cfg.i4_ht_mbs; i++)
        {
            /* job start index y */
            s_job.i2_mb_y = i;

            /* queue the job */
            ret = ih264_list_queue(ps_codec->pv_proc_jobq, &s_job, 1);
            if (ret != IH264_SUCCESS)
            {
                ps_codec->i4_error_code = ret;
                return IH264E_FAIL;
            }
        }

        /* Once all the jobs are queued, terminate the queue */
        /* Since the threads are created and deleted in each call, terminating
        here is not an issue */
        ih264_list_terminate(ps_codec->pv_proc_jobq);
    }

    return error_status;
}