/******************************************************************************
 *
 * 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 Name         : mpeg2dec_api_utils.c                                 */
/*                                                                           */
/*                                                                           */
/*  Description       : This file defines the API interface for MPEG2 Decoder*/
/*                                                                           */
/*  List of Functions : <List the functions defined in this file>            */
/*                                                                           */
/*  Issues / Problems : None                                                 */
/*                                                                           */
/*  Revision History  :                                                      */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         17 09 2007  Rajendra C Y       Creation                           */
/*                                                                           */
/*****************************************************************************/

/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/
/* System include files */

#include <stddef.h>
#include <stdio.h>
#include <string.h>

/* User include files */
#include "iv_datatypedef.h"
#include "iv.h"
#include "ivd.h"
#include "ithread.h"

#include "impeg2_job_queue.h"
#include "impeg2_macros.h"
#include "impeg2_buf_mgr.h"
#include "impeg2_disp_mgr.h"
#include "impeg2_defs.h"
#include "impeg2_platform_macros.h"
#include "impeg2_inter_pred.h"
#include "impeg2_idct.h"
#include "impeg2_format_conv.h"
#include "impeg2_mem_func.h"

#include "impeg2d.h"
#include "impeg2d_api.h"
#include "impeg2d_bitstream.h"
#include "impeg2d_debug.h"
#include "impeg2d_structs.h"
#include "impeg2d_mc.h"
#include "impeg2d_pic_proc.h"
#include "impeg2d_dec_hdr.h"

void impeg2d_next_start_code(dec_state_t *ps_dec);
void impeg2d_next_code(dec_state_t *ps_dec, UWORD32 u4_start_code_val);

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2d_dec_hdr                                      */
/*                                                                           */
/*  Description   :                                                          */
/*  Inputs        :                                                          */
/*  Globals       :                                                          */
/*  Processing    :                                                          */
/*  Outputs       :                                                          */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         17 09 2007  Rajendra C Y          Draft                           */
/*                                                                           */
/*****************************************************************************/
void impeg2d_dec_hdr(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
                 impeg2d_video_decode_op_t *ps_op)
{

    UWORD32 u4_bits_read;
    dec_state_t *ps_dec;
    UWORD32 u4_size = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;

    ps_dec = (dec_state_t *)pv_dec;
    ps_op->s_ivd_video_decode_op_t.u4_error_code = 0;
    if (u4_size > MAX_BITSTREAM_BUFFER_SIZE)
    {
        u4_size = MAX_BITSTREAM_BUFFER_SIZE;
    }

    memcpy(ps_dec->pu1_input_buffer, ps_ip->s_ivd_video_decode_ip_t.pv_stream_buffer, u4_size);

    impeg2d_bit_stream_init(&(ps_dec->s_bit_stream), ps_dec->pu1_input_buffer,
        u4_size);

    {
        {
            IMPEG2D_ERROR_CODES_T e_error;
            e_error = impeg2d_process_video_header(ps_dec);
            if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
            {
                ps_op->s_ivd_video_decode_op_t.u4_error_code    = e_error;

                u4_bits_read     = impeg2d_bit_stream_num_bits_read(&ps_dec->s_bit_stream);

                ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = u4_bits_read>> 3;
                if(ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed > ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes)
                {
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
                }
                if(ps_op->s_ivd_video_decode_op_t.u4_error_code == 0)
                    ps_op->s_ivd_video_decode_op_t.u4_error_code = e_error;

                if (IMPEG2D_UNSUPPORTED_DIMENSIONS == e_error)
                {
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = 0;
                    ps_dec->u2_header_done = 0;

                    ps_op->s_ivd_video_decode_op_t.u4_pic_ht = ps_dec->u2_reinit_max_height;
                    ps_op->s_ivd_video_decode_op_t.u4_pic_wd = ps_dec->u2_reinit_max_width;
                }
                impeg2d_next_code(ps_dec, SEQUENCE_HEADER_CODE);
                return;
            }
        }
        ps_op->s_ivd_video_decode_op_t.u4_pic_ht = ps_dec->u2_vertical_size;
        ps_op->s_ivd_video_decode_op_t.u4_pic_wd = ps_dec->u2_horizontal_size;

        ps_op->s_ivd_video_decode_op_t.e_pic_type            = IV_NA_FRAME;
        ps_op->s_ivd_video_decode_op_t.u4_error_code        = IV_SUCCESS;

        u4_bits_read     = impeg2d_bit_stream_num_bits_read(&ps_dec->s_bit_stream);
        ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = u4_bits_read>> 3;
        if(ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed > ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes)
        {
            ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
        }
        ps_op->s_ivd_video_decode_op_t.u4_frame_decoded_flag = 0;

        /* Set the stride */
        if (0 == ps_dec->u4_frm_buf_stride)
        {
            ps_dec->u4_frm_buf_stride = ps_dec->u2_horizontal_size;
        }
        /* MOD */
        ps_dec->u2_header_done = 1;

    }
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : impeg2d_dec_frm                                         */
/*                                                                           */
/*  Description   :                                                          */
/*  Inputs        :                                                          */
/*  Globals       :                                                          */
/*  Processing    :                                                          */
/*  Outputs       :                                                          */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         17 09 2007  Rajendra C Y          Draft                           */
/*                                                                           */
/*****************************************************************************/
void impeg2d_dec_frm(void *pv_dec,impeg2d_video_decode_ip_t *ps_ip,
                 impeg2d_video_decode_op_t *ps_op)
{


    stream_t *ps_stream;
    UWORD32 u4_size = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;

    dec_state_t *ps_dec;

    ps_dec = (dec_state_t *)pv_dec;
    ps_op->s_ivd_video_decode_op_t.u4_error_code = 0;
    ps_dec->i4_bytes_consumed = 0;
    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = 0;

    IMPEG2D_FRM_NUM_SET();
    if (u4_size > MAX_BITSTREAM_BUFFER_SIZE)
    {
        u4_size = MAX_BITSTREAM_BUFFER_SIZE;
    }

    memcpy(ps_dec->pu1_input_buffer, ps_ip->s_ivd_video_decode_ip_t.pv_stream_buffer, u4_size);

    ps_dec->pu1_inp_bits_buf = ps_dec->pu1_input_buffer;

    ps_dec->u4_num_inp_bytes = u4_size;
    ps_stream  = &ps_dec->s_bit_stream;

    impeg2d_bit_stream_init(ps_stream, ps_dec->pu1_input_buffer, u4_size);

    /* @ */ /* Updating the bufferID */

    ps_dec->u4_xdmBufID     = ps_ip->s_ivd_video_decode_ip_t.u4_ts;

    {
        IMPEG2D_ERROR_CODES_T e_error;
        /* Process the Bitstream */
        e_error = impeg2d_process_video_bit_stream(ps_dec);
        if ((IMPEG2D_ERROR_CODES_T)IVD_ERROR_NONE != e_error)
        {
            ps_op->s_ivd_video_decode_op_t.u4_error_code    = e_error;

            if ((IMPEG2D_ERROR_CODES_T) IVD_RES_CHANGED == e_error)
            {
                ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_dec->i4_bytes_consumed;
                ps_dec->u2_header_done = 0;
            }
            else if (IMPEG2D_UNSUPPORTED_DIMENSIONS == e_error)
            {
                ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = 0;
                ps_dec->u2_header_done = 0;

                ps_op->s_ivd_video_decode_op_t.u4_pic_ht = ps_dec->u2_reinit_max_height;
                ps_op->s_ivd_video_decode_op_t.u4_pic_wd = ps_dec->u2_reinit_max_width;
            }
            else
            {
                if(ps_dec->i4_num_cores > 1 && 0 != ps_dec->i4_bytes_consumed)
                {
                    /* If the number of bytes consumed has been updated by
                     * get_slice_pos function, then use that. Else, the bytes consumed is
                     * calculated from the offset. The bytes consumed for multi-thread runs
                     * is updated only into ps_dec->i4_bytes_consumed if the get_slice_pos
                     * function has been called. If that function has not run, then we have
                     * encountered an error but still have to consume the bytes in header
                     * decode, etc.
                     */
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_dec->i4_bytes_consumed;
                }
                else
                {
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = (ps_dec->s_bit_stream.u4_offset + 7) >> 3;
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed -= ((size_t)ps_dec->s_bit_stream.pv_bs_buf & 3);
                }

                if(ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed
                                > ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes)
                {
                    ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed =
                                    ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
                }

                impeg2d_next_start_code(ps_dec);
            }

            if(ps_op->s_ivd_video_decode_op_t.u4_error_code == 0)
            {
                ps_op->s_ivd_video_decode_op_t.u4_error_code = e_error;
            }

            return;
        }
    }
    /**************************************************************************/
    /* Remove the bytes left till next start code is encountered              */
    /**************************************************************************/
    ps_op->s_ivd_video_decode_op_t.u4_error_code  = IV_SUCCESS;

    if(ps_dec->i4_num_cores > 1 && 0 != ps_dec->i4_bytes_consumed)
    {
        /* If the number of bytes consumed has been updated by
         * get_slice_pos function, then use that. Else, the bytes consumed is
         * calculated from the offset. The bytes consumed for multi-thread runs
         * is updated only into ps_dec->i4_bytes_consumed if the get_slice_pos
         * function has been called. If that function has not run, then we have
         * encountered an error but still have to consume the bytes in header
         * decode, etc.
         */
        ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_dec->i4_bytes_consumed;
    }
    else
    {
        ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = (ps_dec->s_bit_stream.u4_offset + 7) >> 3;
        ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed -= ((size_t)ps_dec->s_bit_stream.pv_bs_buf & 3);
    }
    if(ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed > ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes)
    {
        ps_op->s_ivd_video_decode_op_t.u4_num_bytes_consumed = ps_ip->s_ivd_video_decode_ip_t.u4_num_Bytes;
    }
    ps_op->s_ivd_video_decode_op_t.u4_pic_ht = ps_dec->u2_vertical_size;
    ps_op->s_ivd_video_decode_op_t.u4_pic_wd = ps_dec->u2_horizontal_size;

        switch(ps_dec->e_pic_type)
        {
        case I_PIC :
            ps_op->s_ivd_video_decode_op_t.e_pic_type = IV_I_FRAME;
            break;

        case P_PIC:
            ps_op->s_ivd_video_decode_op_t.e_pic_type = IV_P_FRAME;
            break;

        case B_PIC:
            ps_op->s_ivd_video_decode_op_t.e_pic_type = IV_B_FRAME;
            break;

        case D_PIC:
            ps_op->s_ivd_video_decode_op_t.e_pic_type = IV_I_FRAME;
            break;

        default :
            ps_op->s_ivd_video_decode_op_t.e_pic_type = IV_FRAMETYPE_DEFAULT;
            break;
        }

        ps_op->s_ivd_video_decode_op_t.u4_frame_decoded_flag = ps_dec->i4_frame_decoded;
        ps_op->s_ivd_video_decode_op_t.u4_new_seq = 0;
        ps_op->s_ivd_video_decode_op_t.u4_error_code = ps_dec->u4_error_code;


}