/******************************************************************************
 *
 * Copyright (C) 2022 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
 *  isvcd_utils.c
 *
 * @brief
 *  Contains routines that handle of start and end of pic processing
 *
 * @author
 *  Kishore
 *
 * @remarks
 *  None
 *
 *******************************************************************************
 */

#include <string.h>
#include "ih264_typedefs.h"
#include "ithread.h"
#include "ih264d_deblocking.h"
#include "ih264d_parse_slice.h"
#include "ih264d_parse_cavlc.h"
#include "ih264d_dpb_manager.h"
#include "ih264d_defs.h"
#include "isvcd_structs.h"
#include "ih264d_mem_request.h"
#include "ih264_typedefs.h"
#include "ih264_macros.h"
#include "ih264_platform_macros.h"
#include "ih264d_tables.h"
#include "ih264d_debug.h"
#include "ih264d_mb_utils.h"
#include "ih264d_error_handler.h"
#include "ih264d_dpb_manager.h"
#include "ih264d_utils.h"
#include "ih264d_defs.h"
#include "ih264d_tables.h"
#include "ih264d_inter_pred.h"
#include "ih264d_dpb_manager.h"
#include "iv.h"
#include "ivd.h"
#include "ih264d_format_conv.h"
#include "ih264_error.h"
#include "ih264_disp_mgr.h"
#include "ih264_buf_mgr.h"
#include "ih264d_utils.h"

WORD32 ih264d_init_dec_mb_grp(dec_struct_t *ps_dec);
/*!
**************************************************************************
* \if Function name : isvcd_free_dynamic_bufs \endif
*
* \brief
*    This function frees dynamic memory allocated by Decoder.
*
* \param ps_dec: Pointer to dec_struct_t.
*
* \return
*    Returns i4_status as returned by MemManager.
*
**************************************************************************
*/
WORD16 isvcd_free_dynamic_bufs(svc_dec_lyr_struct_t *ps_svc_lyr_dec)
{
    dec_struct_t *ps_dec = &ps_svc_lyr_dec->s_dec;
    /* Free any avc dynamic buffers that are allocated */
    ih264d_free_dynamic_bufs(ps_dec);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->pu1_crop_wnd_flag);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->ps_inter_lyr_mb_prms_base);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->ps_il_pred_mv_bank_buf_base);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->pi2_il_residual_resample_luma_base);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->pi2_il_residual_resample_chroma_base);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->ps_svc_frm_mb_info);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->pu2_frm_res_luma_csbp);
    PS_DEC_ALIGNED_FREE(ps_dec, ps_svc_lyr_dec->pu1_svc_base_mode_flag);
    return 0;
}

/*!
**************************************************************************
* \if Function name : isvcd_allocate_dynamic_bufs \endif
*
* \brief
*    This function allocates memory required by Decoder.
*
* \param ps_dec: Pointer to dec_struct_t.
*
* \return
*    Returns i4_status as returned by MemManager.
*
**************************************************************************
*/

WORD16 isvcd_allocate_dynamic_bufs(svc_dec_lyr_struct_t *ps_svc_lyr_dec)
{
    dec_struct_t *ps_dec = &ps_svc_lyr_dec->s_dec;
    WORD16 i16_status = 0;
    UWORD8 uc_frmOrFld = (1 - ps_dec->ps_cur_sps->u1_frame_mbs_only_flag);
    dec_seq_params_t *ps_sps = ps_dec->ps_cur_sps;
    UWORD32 u4_total_mbs = ps_sps->u2_total_num_of_mbs << uc_frmOrFld;
    WORD32 size;
    void *pv_buf;
    void *pv_mem_ctxt = ps_dec->pv_mem_ctxt;
    size = u4_total_mbs;

    i16_status = ih264d_allocate_dynamic_bufs(ps_dec);

    if(i16_status != OK)
    {
        /* Free any dynamic buffers that are allocated */
        ih264d_free_dynamic_bufs(ps_dec);
        ps_dec->i4_error_code = IVD_MEM_ALLOC_FAILED;
        return IVD_MEM_ALLOC_FAILED;
    }
    if(u4_total_mbs == 0)
    {
        return IVD_MEM_ALLOC_FAILED;
    }

    /* Allocate frame level mb info */
    size = sizeof(dec_svc_mb_info_t) * u4_total_mbs;
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    ps_svc_lyr_dec->ps_svc_frm_mb_info = pv_buf;
    memset(ps_svc_lyr_dec->ps_svc_frm_mb_info, 0, size);

    /* Allocate frame level residual luma csbp info */
    size = sizeof(UWORD16) * u4_total_mbs;
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    ps_svc_lyr_dec->pu2_frm_res_luma_csbp = pv_buf;
    memset(ps_svc_lyr_dec->pu2_frm_res_luma_csbp, 0, size);
    ps_svc_lyr_dec->i4_frm_res_luma_csbp_stride = ps_dec->u2_frm_wd_in_mbs;

    /* Allocate frame level residual luma csbp info */
    size = sizeof(UWORD8) * u4_total_mbs;
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    ps_svc_lyr_dec->pu1_svc_base_mode_flag = pv_buf;
    memset(ps_svc_lyr_dec->pu1_svc_base_mode_flag, 0, size);
    ps_svc_lyr_dec->i4_frm_svc_base_mode_cabac_stride = ps_dec->u2_frm_wd_in_mbs;
    ps_svc_lyr_dec->i4_frm_svc_base_mode_cabac_size = u4_total_mbs;

    /* Allocate frame level crop windows flags */
    size = sizeof(UWORD8) * u4_total_mbs;
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    ps_svc_lyr_dec->pu1_crop_wnd_flag = pv_buf;
    memset(ps_svc_lyr_dec->pu1_crop_wnd_flag, 0, size);

    /**********************************/
    /*Creation of Inter layer buffers */
    /**********************************/

    /* MB type buffer : one element per MB */
    size = (ps_dec->u2_frm_wd_in_mbs + 2) * (ps_dec->u2_frm_ht_in_mbs + 2) *
           sizeof(inter_lyr_mb_prms_t);
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    memset(pv_buf, -1, size);
    ps_svc_lyr_dec->ps_inter_lyr_mb_prms_base = pv_buf;
    ps_svc_lyr_dec->u2_inter_lyr_mb_prms_stride = ps_dec->u2_frm_wd_in_mbs + 2;
    ps_svc_lyr_dec->ps_inter_lyr_mb_prms_frm_start =
        ps_svc_lyr_dec->ps_inter_lyr_mb_prms_base + 1 + ps_svc_lyr_dec->u2_inter_lyr_mb_prms_stride;

    ps_svc_lyr_dec->u4_inter_lyr_mb_prms_size = (ps_dec->u2_frm_wd_in_mbs + 2) *
                                                (ps_dec->u2_frm_ht_in_mbs + 2) *
                                                sizeof(inter_lyr_mb_prms_t);

    /* Luma Residual data at each layer : dafault 0*/
    size = ((ps_dec->u2_pic_wd + 4) * (ps_dec->u2_pic_ht + 4)) * sizeof(WORD16);
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    memset(pv_buf, 0, size);
    ps_svc_lyr_dec->pi2_il_residual_resample_luma_base = pv_buf;
    ps_svc_lyr_dec->u2_residual_resample_luma_stride = (ps_dec->u2_pic_wd + 4);
    ps_svc_lyr_dec->pi2_il_residual_resample_mb_luma_frm_start =
        ps_svc_lyr_dec->pi2_il_residual_resample_luma_base + 2 +
        (2 * ps_svc_lyr_dec->u2_residual_resample_luma_stride);
    ps_svc_lyr_dec->u4_residual_resample_luma_size =
        ((ps_dec->u2_pic_wd + 4) * (ps_dec->u2_pic_ht + 4)) * sizeof(WORD16);

    /* Chroma Residual data at each layer : dafault 0*/
    size = (((4 + ps_dec->u2_pic_wd) * ((4 + ps_dec->u2_pic_ht) >> 1)) * sizeof(WORD16));
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    memset(pv_buf, 0, size);
    ps_svc_lyr_dec->pi2_il_residual_resample_chroma_base = pv_buf;
    ps_svc_lyr_dec->u2_residual_resample_chroma_stride = (ps_dec->u2_pic_wd + 4);
    ps_svc_lyr_dec->pi2_il_residual_resample_mb_chroma_frm_start =
        ps_svc_lyr_dec->pi2_il_residual_resample_chroma_base + 2 +
        ps_svc_lyr_dec->u2_residual_resample_chroma_stride;
    ps_svc_lyr_dec->u4_residual_resample_chroma_size =
        (((4 + ps_dec->u2_pic_wd) * ((4 + ps_dec->u2_pic_ht) >> 1)) * sizeof(WORD16));

    /* mv bank buffer : 16 elements per MB: each at 4x4 block level */
    size = ((ps_dec->u2_pic_wd) * (ps_dec->u2_pic_ht >> 4)) * sizeof(mv_pred_t);
    pv_buf = ps_dec->pf_aligned_alloc(pv_mem_ctxt, 128, size);
    RETURN_IF((NULL == pv_buf), IV_FAIL);
    memset(pv_buf, 0, size);
    ps_svc_lyr_dec->ps_il_pred_mv_bank_buf_base = pv_buf;

    /*syntax for SVC related bin ctxt tables*/
    {
        bin_ctxt_model_t *const p_cabac_ctxt_table_t = ps_dec->p_cabac_ctxt_table_t;

        ps_svc_lyr_dec->ps_base_mode_flag = p_cabac_ctxt_table_t + CABAC_BASE_MODE_FLAG;
        ps_svc_lyr_dec->ps_motion_prediction_flag_l0 = p_cabac_ctxt_table_t + CABAC_MOT_PRED_FLAG0;
        ps_svc_lyr_dec->ps_motion_prediction_flag_l1 = p_cabac_ctxt_table_t + CABAC_MOT_PRED_FLAG1;
        ps_svc_lyr_dec->ps_residual_prediction_flag = p_cabac_ctxt_table_t + CABAC_RES_PRED_FLAG;
    }
    return (i16_status);
}

/*!
**************************************************************************
* \if Function name : isvcd_decode_pic_order_cnt \endif
*
* \brief
*    Calculates picture order count of picture.
*
* \return
*    Returns the pic order count of the picture to which current
*    Slice belongs.
*
**************************************************************************
*/
WORD32 isvcd_decode_pic_order_cnt(
    UWORD8 u1_is_idr_slice, UWORD32 u2_frame_num, pocstruct_t *ps_prev_poc, pocstruct_t *ps_cur_poc,
    dec_slice_params_t *ps_cur_slice, /*!< Pointer to current slice Params*/
    dec_pic_params_t *ps_pps, UWORD8 u1_nal_ref_idc, UWORD8 u1_bottom_field_flag,
    UWORD8 u1_field_pic_flag, WORD32 *pi4_poc, dec_struct_t *ps_dec)
{
    WORD64 i8_pic_msb;
    WORD32 i4_top_field_order_cnt = 0, i4_bottom_field_order_cnt = 0;
    dec_seq_params_t *ps_seq = ps_dec->ps_cur_sps;
    WORD32 i4_prev_frame_num_ofst;

    switch(ps_seq->u1_pic_order_cnt_type)
    {
        case 0:
            /* POC TYPE 0 */
            if(u1_is_idr_slice)
            {
                ps_prev_poc->i4_pic_order_cnt_msb = 0;
                ps_prev_poc->i4_pic_order_cnt_lsb = 0;
            }
            if(ps_prev_poc->u1_mmco_equalto5)
            {
                if(ps_prev_poc->u1_bot_field != 1)
                {
                    ps_prev_poc->i4_pic_order_cnt_msb = 0;
                    ps_prev_poc->i4_pic_order_cnt_lsb = ps_prev_poc->i4_top_field_order_count;
                }
                else
                {
                    ps_prev_poc->i4_pic_order_cnt_msb = 0;
                    ps_prev_poc->i4_pic_order_cnt_lsb = 0;
                }
            }

            if((ps_cur_poc->i4_pic_order_cnt_lsb < ps_prev_poc->i4_pic_order_cnt_lsb) &&
               ((ps_prev_poc->i4_pic_order_cnt_lsb - ps_cur_poc->i4_pic_order_cnt_lsb) >=
                (ps_seq->i4_max_pic_order_cntLsb >> 1)))
            {
                i8_pic_msb =
                    (WORD64) ps_prev_poc->i4_pic_order_cnt_msb + ps_seq->i4_max_pic_order_cntLsb;
            }
            else if((ps_cur_poc->i4_pic_order_cnt_lsb > ps_prev_poc->i4_pic_order_cnt_lsb) &&
                    ((ps_cur_poc->i4_pic_order_cnt_lsb - ps_prev_poc->i4_pic_order_cnt_lsb) >=
                     (ps_seq->i4_max_pic_order_cntLsb >> 1)))
            {
                i8_pic_msb =
                    (WORD64) ps_prev_poc->i4_pic_order_cnt_msb - ps_seq->i4_max_pic_order_cntLsb;
            }
            else
            {
                i8_pic_msb = ps_prev_poc->i4_pic_order_cnt_msb;
            }

            if(!u1_field_pic_flag || !u1_bottom_field_flag)
            {
                WORD64 i8_result = i8_pic_msb + ps_cur_poc->i4_pic_order_cnt_lsb;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_POC;
                }
                i4_top_field_order_cnt = (WORD32) i8_result;
            }

            if(!u1_field_pic_flag)
            {
                WORD64 i8_result =
                    (WORD64) i4_top_field_order_cnt + ps_cur_poc->i4_delta_pic_order_cnt_bottom;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_POC;
                }
                i4_bottom_field_order_cnt = (WORD32) i8_result;
            }
            else if(u1_bottom_field_flag)
            {
                WORD64 i8_result = i8_pic_msb + ps_cur_poc->i4_pic_order_cnt_lsb;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_POC;
                }
                i4_bottom_field_order_cnt = (WORD32) i8_result;
            }

            if(IS_OUT_OF_RANGE_S32(i8_pic_msb))
            {
                return ERROR_INV_POC;
            }
            ps_cur_poc->i4_pic_order_cnt_msb = (WORD32) i8_pic_msb;
            break;

        case 1:
        {
            /* POC TYPE 1 */
            UWORD8 i;
            WORD32 prev_frame_num;
            WORD32 frame_num_ofst;
            WORD32 abs_frm_num;
            WORD32 poc_cycle_cnt, frame_num_in_poc_cycle;
            WORD64 i8_expected_delta_poc_cycle;
            WORD32 expected_poc;
            WORD64 i8_result;

            prev_frame_num = (WORD32) ps_cur_slice->u2_frame_num;
            if(!u1_is_idr_slice)
            {
                if(ps_cur_slice->u1_mmco_equalto5)
                {
                    prev_frame_num = 0;
                    i4_prev_frame_num_ofst = 0;
                }
                else
                {
                    i4_prev_frame_num_ofst = ps_prev_poc->i4_prev_frame_num_ofst;
                }
            }
            else
                i4_prev_frame_num_ofst = 0;

            /* 1. Derivation for FrameNumOffset */
            if(u1_is_idr_slice)
            {
                frame_num_ofst = 0;
                ps_cur_poc->i4_delta_pic_order_cnt[0] = 0;
                ps_cur_poc->i4_delta_pic_order_cnt[1] = 0;
            }
            else if(prev_frame_num > ((WORD32) u2_frame_num))
            {
                WORD64 i8_result =
                    i4_prev_frame_num_ofst + (WORD64) ps_seq->u2_u4_max_pic_num_minus1 + 1;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_FRAME_NUM;
                }
                frame_num_ofst = (WORD32) i8_result;
            }
            else
                frame_num_ofst = i4_prev_frame_num_ofst;

            /* 2. Derivation for absFrameNum */
            if(0 != ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle)
            {
                WORD64 i8_result = frame_num_ofst + (WORD64) u2_frame_num;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_FRAME_NUM;
                }
                abs_frm_num = (WORD32) i8_result;
            }
            else
                abs_frm_num = 0;
            if((u1_nal_ref_idc == 0) && (abs_frm_num > 0)) abs_frm_num = abs_frm_num - 1;

            /* 4. expectedDeltaPerPicOrderCntCycle is derived as */
            i8_expected_delta_poc_cycle = 0;
            for(i = 0; i < ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle; i++)
            {
                i8_expected_delta_poc_cycle += ps_seq->i4_ofst_for_ref_frame[i];
            }

            /* 3. When absFrameNum > 0, picOrderCntCycleCnt and
            frame_num_in_poc_cycle are derived as : */
            /* 5. expectedPicOrderCnt is derived as : */
            if(abs_frm_num > 0)
            {
                poc_cycle_cnt =
                    DIV((abs_frm_num - 1), ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);
                frame_num_in_poc_cycle =
                    MOD((abs_frm_num - 1), ps_seq->u1_num_ref_frames_in_pic_order_cnt_cycle);

                i8_result = poc_cycle_cnt * i8_expected_delta_poc_cycle;

                for(i = 0; i <= frame_num_in_poc_cycle; i++)
                {
                    i8_result = i8_result + ps_seq->i4_ofst_for_ref_frame[i];
                }

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;

                expected_poc = (WORD32) i8_result;
            }
            else
                expected_poc = 0;

            if(u1_nal_ref_idc == 0)
            {
                i8_result = (WORD64) expected_poc + ps_seq->i4_ofst_for_non_ref_pic;

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;

                expected_poc = (WORD32) i8_result;
            }

            /* 6. TopFieldOrderCnt or BottomFieldOrderCnt are derived as */
            if(!u1_field_pic_flag)
            {
                i8_result = (WORD64) expected_poc + ps_cur_poc->i4_delta_pic_order_cnt[0];

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;
                i4_top_field_order_cnt = (WORD32) i8_result;

                i8_result = (WORD64) i4_top_field_order_cnt +
                            ps_seq->i4_ofst_for_top_to_bottom_field +
                            ps_cur_poc->i4_delta_pic_order_cnt[1];

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;
                i4_bottom_field_order_cnt = (WORD32) i8_result;
            }
            else if(!u1_bottom_field_flag)
            {
                i8_result = (WORD64) expected_poc + ps_cur_poc->i4_delta_pic_order_cnt[0];

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;
                i4_top_field_order_cnt = (WORD32) i8_result;
            }
            else
            {
                i8_result = (WORD64) expected_poc + ps_seq->i4_ofst_for_top_to_bottom_field +
                            ps_cur_poc->i4_delta_pic_order_cnt[0];

                if(IS_OUT_OF_RANGE_S32(i8_result)) return ERROR_INV_POC;
                i4_bottom_field_order_cnt = (WORD32) i8_result;
            }
            /* Copy the current POC info into Previous POC structure */
            ps_cur_poc->i4_prev_frame_num_ofst = frame_num_ofst;
        }

        break;
        case 2:
        {
            /* POC TYPE 2 */
            WORD32 prev_frame_num;
            WORD32 frame_num_ofst;
            WORD32 tmp_poc;

            prev_frame_num = (WORD32) ps_cur_slice->u2_frame_num;
            if(!u1_is_idr_slice)
            {
                if(ps_cur_slice->u1_mmco_equalto5)
                {
                    prev_frame_num = 0;
                    i4_prev_frame_num_ofst = 0;
                }
                else
                    i4_prev_frame_num_ofst = ps_prev_poc->i4_prev_frame_num_ofst;
            }
            else
                i4_prev_frame_num_ofst = 0;

            /* 1. Derivation for FrameNumOffset */
            if(u1_is_idr_slice)
            {
                frame_num_ofst = 0;
                ps_cur_poc->i4_delta_pic_order_cnt[0] = 0;
                ps_cur_poc->i4_delta_pic_order_cnt[1] = 0;
            }
            else if(prev_frame_num > ((WORD32) u2_frame_num))
            {
                WORD64 i8_result =
                    i4_prev_frame_num_ofst + (WORD64) ps_seq->u2_u4_max_pic_num_minus1 + 1;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_FRAME_NUM;
                }
                frame_num_ofst = (WORD32) i8_result;
            }
            else
                frame_num_ofst = i4_prev_frame_num_ofst;

            /* 2. Derivation for tempPicOrderCnt */
            if(u1_is_idr_slice)
                tmp_poc = 0;
            else if(u1_nal_ref_idc == 0)
            {
                WORD64 i8_result = ((frame_num_ofst + (WORD64) u2_frame_num) << 1) - 1;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_POC;
                }
                tmp_poc = (WORD32) i8_result;
            }
            else
            {
                WORD64 i8_result = (frame_num_ofst + (WORD64) u2_frame_num) << 1;
                if(IS_OUT_OF_RANGE_S32(i8_result))
                {
                    return ERROR_INV_POC;
                }
                tmp_poc = (WORD32) i8_result;
            }

            /* 6. TopFieldOrderCnt or BottomFieldOrderCnt are derived as */
            if(!u1_field_pic_flag)
            {
                i4_top_field_order_cnt = tmp_poc;
                i4_bottom_field_order_cnt = tmp_poc;
            }
            else if(!u1_bottom_field_flag)
                i4_top_field_order_cnt = tmp_poc;
            else
                i4_bottom_field_order_cnt = tmp_poc;

            /* Copy the current POC info into Previous POC structure */
            ps_prev_poc->i4_prev_frame_num_ofst = frame_num_ofst;
            ps_cur_poc->i4_prev_frame_num_ofst = frame_num_ofst;
        }
        break;
        default:
            return ERROR_INV_POC_TYPE_T;
            break;
    }

    if(!u1_field_pic_flag)  // or a complementary field pair
    {
        *pi4_poc = MIN(i4_top_field_order_cnt, i4_bottom_field_order_cnt);
        ps_pps->i4_top_field_order_cnt = i4_top_field_order_cnt;
        ps_pps->i4_bottom_field_order_cnt = i4_bottom_field_order_cnt;
    }
    else if(!u1_bottom_field_flag)
    {
        *pi4_poc = i4_top_field_order_cnt;
        ps_pps->i4_top_field_order_cnt = i4_top_field_order_cnt;
    }
    else
    {
        *pi4_poc = i4_bottom_field_order_cnt;
        ps_pps->i4_bottom_field_order_cnt = i4_bottom_field_order_cnt;
    }

    ps_pps->i4_avg_poc = *pi4_poc;

    return OK;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : isvcd_decode_gaps_in_frame_num */
/*                                                                           */
/*  Description   : This function decodes gaps in frame number               */
/*                                                                           */
/*  Inputs        : ps_dec          Decoder parameters                       */
/*                  u2_frame_num   current frame number                     */
/*                                                                           */
/*  Globals       : None                                                     */
/*  Processing    : This functionality needs to be implemented               */
/*  Outputs       : None                                                     */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : Not implemented                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         06 05 2002   NS              Draft                                */
/*                                                                           */
/*****************************************************************************/
WORD32 isvcd_decode_gaps_in_frame_num(dec_struct_t *ps_dec, UWORD16 u2_frame_num)
{
    UWORD32 u4_next_frm_num, u4_start_frm_num;
    UWORD32 u4_max_frm_num;
    pocstruct_t s_tmp_poc;
    WORD32 i4_poc;
    dec_slice_params_t *ps_cur_slice;

    dec_pic_params_t *ps_pic_params;
    WORD8 i1_gap_idx;
    WORD32 *i4_gaps_start_frm_num;
    dpb_manager_t *ps_dpb_mgr;
    WORD8 *pi1_gaps_per_seq;
    WORD32 ret;

    ps_cur_slice = ps_dec->ps_cur_slice;
    if(ps_cur_slice->u1_field_pic_flag)
    {
        if(ps_dec->u2_prev_ref_frame_num == u2_frame_num) return 0;
    }

    u4_next_frm_num = ps_dec->u2_prev_ref_frame_num + 1;
    u4_max_frm_num = ps_dec->ps_cur_sps->u2_u4_max_pic_num_minus1 + 1;

    if(u4_next_frm_num >= u4_max_frm_num)
    {
        u4_next_frm_num -= u4_max_frm_num;
    }

    if(u4_next_frm_num == u2_frame_num)
    {
        return (0);
    }

    if((ps_dec->u1_nal_unit_type == IDR_SLICE_NAL) && (u4_next_frm_num >= u2_frame_num))
    {
        return (0);
    }
    u4_start_frm_num = u4_next_frm_num;

    s_tmp_poc.i4_pic_order_cnt_lsb = 0;
    s_tmp_poc.i4_delta_pic_order_cnt_bottom = 0;
    s_tmp_poc.i4_pic_order_cnt_lsb = 0;
    s_tmp_poc.i4_delta_pic_order_cnt_bottom = 0;
    s_tmp_poc.i4_delta_pic_order_cnt[0] = 0;
    s_tmp_poc.i4_delta_pic_order_cnt[1] = 0;

    ps_cur_slice = ps_dec->ps_cur_slice;
    ps_pic_params = ps_dec->ps_cur_pps;

    ps_dpb_mgr = ps_dec->ps_dpb_mgr;

    /* Find a empty slot to store gap seqn info */
    i4_gaps_start_frm_num = ps_dpb_mgr->ai4_gaps_start_frm_num;
    for(i1_gap_idx = 0; i1_gap_idx < MAX_FRAMES; i1_gap_idx++)
    {
        if(INVALID_FRAME_NUM == i4_gaps_start_frm_num[i1_gap_idx]) break;
    }
    if(MAX_FRAMES == i1_gap_idx)
    {
        UWORD32 i4_error_code;
        i4_error_code = ERROR_DBP_MANAGER_T;
        return i4_error_code;
    }

    i4_poc = 0;
    i4_gaps_start_frm_num[i1_gap_idx] = u4_start_frm_num;
    ps_dpb_mgr->ai4_gaps_end_frm_num[i1_gap_idx] = u2_frame_num - 1;
    pi1_gaps_per_seq = ps_dpb_mgr->ai1_gaps_per_seq;
    pi1_gaps_per_seq[i1_gap_idx] = 0;
    while(u4_next_frm_num != u2_frame_num)
    {
        ih264d_delete_nonref_nondisplay_pics(ps_dpb_mgr);
        if(ps_pic_params->ps_sps->u1_pic_order_cnt_type)
        {
            /* allocate a picture buffer and insert it as ST node */
            ret =
                isvcd_decode_pic_order_cnt(0, u4_next_frm_num, &ps_dec->s_prev_pic_poc, &s_tmp_poc,
                                           ps_cur_slice, ps_pic_params, 1, 0, 0, &i4_poc, ps_dec);
            if(ret != OK) return ret;

            /* Display seq no calculations */
            if(i4_poc >= ps_dec->i4_max_poc) ps_dec->i4_max_poc = i4_poc;
            /* IDR Picture or POC wrap around */
            if(i4_poc == 0)
            {
                WORD64 i8_temp;
                i8_temp = (WORD64) ps_dec->i4_prev_max_display_seq + ps_dec->i4_max_poc +
                          ps_dec->u1_max_dec_frame_buffering + 1;
                /*If i4_prev_max_display_seq overflows integer range, reset it */
                ps_dec->i4_prev_max_display_seq =
                    IS_OUT_OF_RANGE_S32(i8_temp) ? 0 : (WORD32) i8_temp;
                ps_dec->i4_max_poc = 0;
            }

            ps_cur_slice->u1_mmco_equalto5 = 0;
            ps_cur_slice->u2_frame_num = u4_next_frm_num;
        }

        if(ps_dpb_mgr->i1_poc_buf_id_entries >= ps_dec->u1_max_dec_frame_buffering)
        {
            ret = ih264d_assign_display_seq(ps_dec);
            if(ret != OK) return ret;
        }

        {
            WORD64 i8_display_poc;
            i8_display_poc = (WORD64) ps_dec->i4_prev_max_display_seq + i4_poc;
            if(IS_OUT_OF_RANGE_S32(i8_display_poc))
            {
                ps_dec->i4_prev_max_display_seq = 0;
            }
        }
        ret = ih264d_insert_pic_in_display_list(ps_dec->ps_dpb_mgr, (WORD8) DO_NOT_DISP,
                                                (WORD32) (ps_dec->i4_prev_max_display_seq + i4_poc),
                                                u4_next_frm_num);
        if(ret != OK) return ret;

        pi1_gaps_per_seq[i1_gap_idx]++;
        ret = ih264d_do_mmco_for_gaps(ps_dpb_mgr, ps_dec->ps_cur_sps->u1_num_ref_frames);
        if(ret != OK) return ret;

        ih264d_delete_nonref_nondisplay_pics(ps_dpb_mgr);

        u4_next_frm_num++;
        if(u4_next_frm_num >= u4_max_frm_num)
        {
            u4_next_frm_num -= u4_max_frm_num;
        }
    }

    return OK;
}

/*!
**************************************************************************
* \if Function name : isvcd_init_pic \endif
*
* \brief
*    Initializes the picture.
*
* \return
*    0 on Success and Error code otherwise
*
* \note
*    This function is called when first slice of the
*    NON -IDR picture is encountered.
**************************************************************************
*/
WORD32 isvcd_init_pic(svc_dec_lyr_struct_t *ps_svc_lyr_dec, UWORD16 u2_frame_num, WORD32 i4_poc,
                      dec_pic_params_t *ps_pps)
{
    dec_struct_t *ps_dec = &ps_svc_lyr_dec->s_dec;
    dec_seq_params_t *ps_seq = ps_dec->ps_cur_sps;
    prev_seq_params_t *ps_prev_seq_params = &ps_dec->s_prev_seq_params;
    WORD32 ret;

    ps_dec->ps_cur_slice->u2_frame_num = u2_frame_num;
    ps_dec->ps_cur_slice->i4_poc = i4_poc;
    ps_dec->ps_cur_pps = ps_pps;
    ps_dec->ps_cur_pps->pv_codec_handle = ps_dec;

    ps_dec->ps_dpb_mgr->i4_max_frm_num = ps_seq->u2_u4_max_pic_num_minus1 + 1;

    ps_dec->ps_dpb_mgr->u2_pic_ht = ps_dec->u2_pic_ht;
    ps_dec->ps_dpb_mgr->u2_pic_wd = ps_dec->u2_pic_wd;
    ps_dec->i4_pic_type = NA_SLICE;
    ps_dec->i4_frametype = IV_NA_FRAME;
    ps_dec->i4_content_type = IV_CONTENTTYPE_NA;

    /*--------------------------------------------------------------------*/
    /* Get the value of MaxMbAddress and frmheight in Mbs                 */
    /*--------------------------------------------------------------------*/
    ps_seq->u2_max_mb_addr =
        (ps_seq->u2_frm_wd_in_mbs *
         (ps_dec->u2_pic_ht >> (4 + ps_dec->ps_cur_slice->u1_field_pic_flag))) -
        1;
    ps_dec->u2_frm_ht_in_mbs = (ps_dec->u2_pic_ht >> (4 + ps_dec->ps_cur_slice->u1_field_pic_flag));

    /***************************************************************************/
    /* If change in Level or the required PicBuffers i4_size is more than the  */
    /* current one FREE the current PicBuffers and allocate affresh            */
    /***************************************************************************/
    if(!ps_dec->u1_init_dec_flag)
    {
        ps_dec->u1_max_dec_frame_buffering = ih264d_get_dpb_size(ps_seq);

        ps_dec->i4_display_delay = ps_dec->u1_max_dec_frame_buffering;
        if((1 == ps_seq->u1_vui_parameters_present_flag) &&
           (1 == ps_seq->s_vui.u1_bitstream_restriction_flag))
        {
            if(ps_seq->u1_frame_mbs_only_flag == 1)
                ps_dec->i4_display_delay = ps_seq->s_vui.u4_num_reorder_frames + 1;
            else
                ps_dec->i4_display_delay = ps_seq->s_vui.u4_num_reorder_frames * 2 + 2;
        }

        if(IVD_DECODE_FRAME_OUT == ps_dec->e_frm_out_mode) ps_dec->i4_display_delay = 0;

        if(ps_dec->u4_share_disp_buf == 0)
        {
            if(ps_seq->u1_frame_mbs_only_flag == 1)
                ps_dec->u1_pic_bufs = ps_dec->i4_display_delay + ps_seq->u1_num_ref_frames + 1;
            else
                ps_dec->u1_pic_bufs = ps_dec->i4_display_delay + ps_seq->u1_num_ref_frames * 2 + 2;
        }
        else
        {
            ps_dec->u1_pic_bufs = (WORD32) ps_dec->u4_num_disp_bufs;
        }

        /* Ensure at least two buffers are allocated */
        ps_dec->u1_pic_bufs = MAX(ps_dec->u1_pic_bufs, 2);

        if(ps_dec->u4_share_disp_buf == 0)
            ps_dec->u1_pic_bufs = MIN(ps_dec->u1_pic_bufs, (H264_MAX_REF_PICS * 2));

        ps_dec->u1_max_dec_frame_buffering =
            MIN(ps_dec->u1_max_dec_frame_buffering, ps_dec->u1_pic_bufs);

        /* Temporary hack to run Tractor Cav/Cab/MbAff Profiler streams  also for
         * CAFI1_SVA_C.264 in conformance*/
        if(ps_dec->u1_init_dec_flag)
        {
            ih264d_release_pics_in_dpb((void *) ps_dec, ps_dec->u1_pic_bufs);
            ih264d_release_display_bufs(ps_dec);
            ih264d_reset_ref_bufs(ps_dec->ps_dpb_mgr);
        }

        /*********************************************************************/
        /* Configuring decoder parameters based on level and then            */
        /* fresh pointer initialisation in decoder scratch and state buffers */
        /*********************************************************************/
        if(!ps_dec->u1_init_dec_flag || ((ps_seq->u1_level_idc < H264_LEVEL_3_0) ^
                                         (ps_prev_seq_params->u1_level_idc < H264_LEVEL_3_0)))
        {
            ret = ih264d_init_dec_mb_grp(ps_dec);
            if(ret != OK) return ret;
        }

        ret = isvcd_allocate_dynamic_bufs(ps_svc_lyr_dec);

        if(ret != OK)
        {
            /* Free any dynamic buffers that are allocated */
            isvcd_free_dynamic_bufs(ps_svc_lyr_dec);
            ps_dec->i4_error_code = IVD_MEM_ALLOC_FAILED;
            return IVD_MEM_ALLOC_FAILED;
        }

        ret = ih264d_create_pic_buffers(ps_dec->u1_pic_bufs, ps_dec);
        if(ret != OK) return ret;

        ret = ih264d_create_mv_bank(ps_dec, ps_dec->u2_pic_wd, ps_dec->u2_pic_ht);
        if(ret != OK) return ret;

        /* In shared mode, set all of them as used by display */
        if(ps_dec->u4_share_disp_buf == 1)
        {
            WORD32 i;

            for(i = 0; i < ps_dec->u1_pic_bufs; i++)
            {
                ih264_buf_mgr_set_status((buf_mgr_t *) ps_dec->pv_pic_buf_mgr, i, BUF_MGR_IO);
            }
        }

        ps_dec->u1_init_dec_flag = 1;
        ps_prev_seq_params->u2_frm_wd_in_mbs = ps_seq->u2_frm_wd_in_mbs;
        ps_prev_seq_params->u1_level_idc = ps_seq->u1_level_idc;
        ps_prev_seq_params->u1_profile_idc = ps_seq->u1_profile_idc;
        ps_prev_seq_params->u2_frm_ht_in_mbs = ps_seq->u2_frm_ht_in_mbs;
        ps_prev_seq_params->u1_frame_mbs_only_flag = ps_seq->u1_frame_mbs_only_flag;
        ps_prev_seq_params->u1_direct_8x8_inference_flag = ps_seq->u1_direct_8x8_inference_flag;

        ps_dec->i4_cur_display_seq = 0;
        ps_dec->i4_prev_max_display_seq = 0;
        ps_dec->i4_max_poc = 0;

        {
            /* 0th entry of CtxtIncMbMap will be always be containing default values
            for CABAC context representing MB not available */
            ctxt_inc_mb_info_t *p_DefCtxt = ps_dec->p_ctxt_inc_mb_map - 1;
            UWORD8 *pu1_temp;
            WORD8 i;
            p_DefCtxt->u1_mb_type = CAB_SKIP;

            p_DefCtxt->u1_cbp = 0x0f;
            p_DefCtxt->u1_intra_chroma_pred_mode = 0;

            p_DefCtxt->u1_yuv_dc_csbp = 0x7;

            p_DefCtxt->u1_transform8x8_ctxt = 0;

            pu1_temp = (UWORD8 *) p_DefCtxt->i1_ref_idx;
            for(i = 0; i < 4; i++, pu1_temp++) (*pu1_temp) = 0;
            pu1_temp = (UWORD8 *) p_DefCtxt->u1_mv;
            for(i = 0; i < 16; i++, pu1_temp++) (*pu1_temp) = 0;
            ps_dec->ps_def_ctxt_mb_info = p_DefCtxt;
        }
    }
    /* reset DBP commands read u4_flag */
    ps_dec->ps_dpb_cmds->u1_dpb_commands_read = 0;

    return OK;
}
