C++程序  |  3172行  |  126.5 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 Name         : main.c                                               */
/*                                                                           */
/*  Description       : Contains an application that demonstrates use of H264*/
/*                      decoder API                                          */
/*                                                                           */
/*  List of Functions :                                                      */
/*                                                                           */
/*  Issues / Problems : None                                                 */
/*                                                                           */
/*  Revision History  :                                                      */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   Harish          Initial Version                      */
/*****************************************************************************/
/*****************************************************************************/
/* File Includes                                                             */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef X86_MINGW
#include <signal.h>
#endif

#ifndef IOS
#include <malloc.h>
#endif
#ifdef IOS_DISPLAY
#include "cast_types.h"
#else
#include "ih264_typedefs.h"
#endif

#include "iv.h"
#include "ivd.h"
#include "ih264d.h"
#include "ithread.h"

#ifdef WINDOWS_TIMER
#include <windows.h>
#else
#include <sys/time.h>
#endif

//#define ADAPTIVE_TEST
#define ADAPTIVE_MAX_WD 4096
#define ADAPTIVE_MAX_HT 2160

#define ALIGN8(x) ((((x) + 7) >> 3) << 3)
#define NUM_DISPLAY_BUFFERS 4
#define DEFAULT_FPS         30

#define ENABLE_DEGRADE 0
#define MAX_DISP_BUFFERS    64
#define EXTRA_DISP_BUFFERS  8
#define STRLENGTH 1000

//#define TEST_FLUSH
#define FLUSH_FRM_CNT 100
//#define APP_EXTRA_BUFS 1

#ifdef IOS
#define PATHLENMAX 500
char filename_with_path[PATHLENMAX];
#endif

#ifdef PROFILE_ENABLE
    #ifdef WINDOWS_TIMER
        typedef  LARGE_INTEGER TIMER;
    #else
        //#ifdef GCC_TIMER
        typedef struct timeval TIMER;
        //#endif
    #endif
#else
        typedef WORD32 TIMER;
#endif

#ifdef PROFILE_ENABLE
    #ifdef WINDOWS_TIMER
        #define GETTIME(timer) QueryPerformanceCounter(timer);
    #else
    //#ifdef GCC_TIMER
        #define GETTIME(timer) gettimeofday(timer,NULL);
    //#endif
    #endif

    #ifdef WINDOWS_TIMER
        #define ELAPSEDTIME(s_start_timer,s_end_timer, s_elapsed_time, frequency) \
                  { \
                   TIMER s_temp_time;   \
                   s_temp_time.LowPart = s_end_timer.LowPart - s_start_timer.LowPart ; \
                   s_elapsed_time = (UWORD32) ( ((DOUBLE)s_temp_time.LowPart / (DOUBLE)frequency.LowPart )  * 1000000); \
                }
    #else
    //#ifdef GCC_TIMER
        #define ELAPSEDTIME(s_start_timer,s_end_timer, s_elapsed_time, frequency) \
                   s_elapsed_time = ((s_end_timer.tv_sec - s_start_timer.tv_sec) * 1000000) + (s_end_timer.tv_usec - s_start_timer.tv_usec);
    //#endif
    #endif

#else
    #define GETTIME(timer)
    #define ELAPSEDTIME(s_start_timer,s_end_timer, s_elapsed_time, frequency)
#endif


/* Function declarations */
#ifndef MD5_DISABLE
void calc_md5_cksum(UWORD8 *pu1_inbuf,UWORD32 u4_stride,UWORD32 u4_width,UWORD32 u4_height,UWORD8 *pu1_cksum_p );
#else
#define calc_md5_cksum(a, b, c, d, e)
#endif
#ifdef SDL_DISPLAY
void* sdl_disp_init(UWORD32, UWORD32, WORD32, WORD32, WORD32, WORD32, WORD32, WORD32 *, WORD32 *);
void sdl_alloc_disp_buffers(void *);
void sdl_display(void *, WORD32 );
void sdl_set_disp_buffers(void *, WORD32, UWORD8 **, UWORD8 **, UWORD8 **);
void sdl_disp_deinit(void *);
void sdl_disp_usleep(UWORD32);
IV_COLOR_FORMAT_T sdl_get_color_fmt(void);
UWORD32 sdl_get_stride(void);
#endif

#ifdef INTEL_CE5300
void* gdl_disp_init(UWORD32, UWORD32, WORD32, WORD32, WORD32, WORD32, WORD32, WORD32 *, WORD32 *);
void gdl_alloc_disp_buffers(void *);
void gdl_display(void *, WORD32 );
void gdl_set_disp_buffers(void *, WORD32, UWORD8 **, UWORD8 **, UWORD8 **);
void gdl_disp_deinit(void *);
void gdl_disp_usleep(UWORD32);
IV_COLOR_FORMAT_T gdl_get_color_fmt(void);
UWORD32 gdl_get_stride(void);
#endif

#ifdef FBDEV_DISPLAY
void* fbd_disp_init(UWORD32, UWORD32, WORD32, WORD32, WORD32, WORD32, WORD32, WORD32 *, WORD32 *);
void fbd_alloc_disp_buffers(void *);
void fbd_display(void *, WORD32 );
void fbd_set_disp_buffers(void *, WORD32, UWORD8 **, UWORD8 **, UWORD8 **);
void fbd_disp_deinit(void *);
void fbd_disp_usleep(UWORD32);
IV_COLOR_FORMAT_T fbd_get_color_fmt(void);
UWORD32 fbd_get_stride(void);
#endif

#ifdef IOS_DISPLAY
void* ios_disp_init(UWORD32, UWORD32, WORD32, WORD32, WORD32, WORD32, WORD32, WORD32 *, WORD32 *);
void ios_alloc_disp_buffers(void *);
void ios_display(void *, WORD32 );
void ios_set_disp_buffers(void *, WORD32, UWORD8 **, UWORD8 **, UWORD8 **);
void ios_disp_deinit(void *);
void ios_disp_usleep(UWORD32);
IV_COLOR_FORMAT_T ios_get_color_fmt(void);
UWORD32 ios_get_stride(void);
#endif

typedef struct
{
    UWORD32 u4_piclen_flag;
    UWORD32 u4_file_save_flag;
    UWORD32 u4_chksum_save_flag;
    UWORD32 u4_max_frm_ts;
    IV_COLOR_FORMAT_T e_output_chroma_format;
    IVD_ARCH_T e_arch;
    IVD_SOC_T e_soc;
    UWORD32 dump_q_rd_idx;
    UWORD32 dump_q_wr_idx;
    WORD32  disp_q_wr_idx;
    WORD32  disp_q_rd_idx;

    void *cocodec_obj;
    UWORD32 u4_share_disp_buf;
    UWORD32 num_disp_buf;
    UWORD32 b_pic_present;
    UWORD32 u4_disable_dblk_level;
    WORD32 i4_degrade_type;
    WORD32 i4_degrade_pics;
    UWORD32 u4_num_cores;
    UWORD32 disp_delay;
    WORD32 trace_enable;
    CHAR ac_trace_fname[STRLENGTH];
    CHAR ac_piclen_fname[STRLENGTH];
    CHAR ac_ip_fname[STRLENGTH];
    CHAR ac_op_fname[STRLENGTH];
    CHAR ac_op_chksum_fname[STRLENGTH];
    ivd_out_bufdesc_t s_disp_buffers[MAX_DISP_BUFFERS];
    iv_yuv_buf_t s_disp_frm_queue[MAX_DISP_BUFFERS];
    UWORD32 s_disp_frm_id_queue[MAX_DISP_BUFFERS];
    UWORD32 loopback;
    UWORD32 display;
    UWORD32 full_screen;
    UWORD32 fps;

    UWORD32 u4_strd;

    /* For signalling to display thread */
    UWORD32 u4_pic_wd;
    UWORD32 u4_pic_ht;

    /* For IOS diplay */
    WORD32 i4_screen_wd;
    WORD32 i4_screen_ht;

    //UWORD32 u4_output_present;
    WORD32  quit;
    WORD32  paused;


    void *pv_disp_ctx;
    void *display_thread_handle;
    WORD32 display_thread_created;
    volatile WORD32 display_init_done;
    volatile WORD32 display_deinit_flag;

    void *(*disp_init)(UWORD32, UWORD32, WORD32, WORD32, WORD32, WORD32, WORD32, WORD32 *, WORD32 *);
    void (*alloc_disp_buffers)(void *);
    void (*display_buffer)(void *, WORD32);
    void (*set_disp_buffers)(void *, WORD32, UWORD8 **, UWORD8 **, UWORD8 **);
    void (*disp_deinit)(void *);
    void (*disp_usleep)(UWORD32);
    IV_COLOR_FORMAT_T (*get_color_fmt)(void);
    UWORD32 (*get_stride)(void);
} vid_dec_ctx_t;



typedef enum
{
    INVALID,
    HELP,
    VERSION,
    INPUT_FILE,
    OUTPUT,
    CHKSUM,
    SAVE_OUTPUT,
    SAVE_CHKSUM,
    CHROMA_FORMAT,
    NUM_FRAMES,
    NUM_CORES,
    DISABLE_DEBLOCK_LEVEL,
    SHARE_DISPLAY_BUF,
    LOOPBACK,
    DISPLAY,
    FULLSCREEN,
    FPS,
    TRACE,
    CONFIG,

    DEGRADE_TYPE,
    DEGRADE_PICS,
    ARCH,
    SOC,
    PICLEN,
    PICLEN_FILE,
} ARGUMENT_T;

typedef struct
{
    CHAR argument_shortname[4];
    CHAR argument_name[128];
    ARGUMENT_T argument;
    CHAR description[512];
} argument_t;

static const argument_t argument_mapping[] =
{
    {"-h",  "--help",                   HELP,
         "Print this help\n"},
    { "-c", "--config",      CONFIG,
         "config file (Default: test.cfg)\n" },

    {"-v",  "--version",                VERSION,
         "Version information\n"},
    {"-i",  "--input",                  INPUT_FILE,
         "Input file\n"},
    {"-o",  "--output",                 OUTPUT,
         "Output file\n"},
    {"--",  "--piclen",                 PICLEN,
          "Flag to signal if the decoder has to use a file containing number of bytes in each picture to be fed in each call\n"},
    {"--",  "--piclen_file",                 PICLEN_FILE,
            "File containing number of bytes in each picture - each line containing one i4_size\n"},
    {"--",  "--chksum",          CHKSUM,
         "Output MD5 Checksum file\n"},
    { "-s", "--save_output",            SAVE_OUTPUT,
          "Save Output file\n" },
    { "--", "--save_chksum",            SAVE_CHKSUM,
          "Save Check sum file\n" },
    {"--",  "--chroma_format",          CHROMA_FORMAT,
         "Output Chroma format Supported values YUV_420P, YUV_422ILE, RGB_565, YUV_420SP_UV, YUV_420SP_VU\n" },
    { "-n", "--num_frames",             NUM_FRAMES,
         "Number of frames to be decoded\n" },
    { "--", "--num_cores",              NUM_CORES,
          "Number of cores to be used\n" },
    { "--", "--share_display_buf",      SHARE_DISPLAY_BUF,
          "Enable shared display buffer mode\n" },
    {"--", "--disable_deblock_level", DISABLE_DEBLOCK_LEVEL,
         "Disable deblocking level : 0 to 4 - 0 Enable deblocking 4 Disable deblocking completely\n"},
    { "--", "--loopback",      LOOPBACK,
        "Enable playback in a loop\n" },
    { "--", "--display",      DISPLAY,
        "Enable display (uses SDL)\n" },
     { "--", "--fullscreen",      FULLSCREEN,
        "Enable full screen (Only for GDL and SDL)\n" },
    { "--", "--fps",      FPS,
        "FPS to be used for display \n" },
    {"-i",  "--trace",                   TRACE,
         "Trace file\n"},

    {"--",  "--degrade_type",  DEGRADE_TYPE,
         "Degrade type : 0: No degrade 0th bit set : Disable SAO 1st bit set : Disable deblocking 2nd bit set : Faster inter prediction filters 3rd bit set : Fastest inter prediction filters\n" },
    {"--",  "--degrade_pics",  DEGRADE_PICS,
         "Degrade pics : 0 : No degrade  1 : Only on non-reference frames  2 : Do not degrade every 4th or key frames  3 : All non-key frames  4 : All frames"},

    {"--",  "--arch", ARCH,
         "Set Architecture. Supported values  ARM_NONEON, ARM_A9Q, ARM_A7, ARM_A5, ARM_NEONINTR,ARMV8_GENERIC, X86_GENERIC, X86_SSSE3, X86_SSE4 \n" },
    {"--",  "--soc", SOC,
         "Set SOC. Supported values  GENERIC, HISI_37X \n" },

};

#define PEAK_WINDOW_SIZE            8
#define DEFAULT_SHARE_DISPLAY_BUF   0
#define STRIDE                      0
#define DEFAULT_NUM_CORES           1


#define DUMP_SINGLE_BUF 0
#define IV_ISFATALERROR(x)         (((x) >> IVD_FATALERROR) & 0x1)

#define ivd_api_function        ih264d_api_function

#ifdef IOS
char filename_trace[PATHLENMAX];
#endif

#if ANDROID_NDK
/*****************************************************************************/
/*                                                                           */
/*  Function Name : raise                                                    */
/*                                                                           */
/*  Description   : Needed as a workaround when the application is built in  */
/*                  Android NDK. This is an exception to be called for divide*/
/*                  by zero error                                            */
/*                                                                           */
/*  Inputs        : a                                                        */
/*  Globals       :                                                          */
/*  Processing    : None                                                     */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/
int raise(int a)
{
    printf("Divide by zero\n");
    return 0;
}
#endif

#ifdef _WIN32
/*****************************************************************************/
/* Function to print library calls                                           */
/*****************************************************************************/
/*****************************************************************************/
/*                                                                           */
/*  Function Name : memalign                                                 */
/*                                                                           */
/*  Description   : Returns malloc data. Ideally should return aligned memory*/
/*                  support alignment will be added later                    */
/*                                                                           */
/*  Inputs        : alignment                                                */
/*                  i4_size                                                     */
/*  Globals       :                                                          */
/*  Processing    :                                                          */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

void * ih264a_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size)
{
    (void)pv_ctxt;
    return (void *)_aligned_malloc(i4_size, alignment);
}

void ih264a_aligned_free(void *pv_ctxt, void *pv_buf)
{
    (void)pv_ctxt;
    _aligned_free(pv_buf);
    return;
}
#endif

#if IOS
void * ih264a_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size)
{
    (void)pv_ctxt;
    return malloc(i4_size);
}

void ih264a_aligned_free(void *pv_ctxt, void *pv_buf)
{
    (void)pv_ctxt;
    free(pv_buf);
    return;
}
#endif

#if (!defined(IOS)) && (!defined(_WIN32))
void * ih264a_aligned_malloc(void *pv_ctxt, WORD32 alignment, WORD32 i4_size)
{
   (void)pv_ctxt;
    return memalign(alignment, i4_size);
}

void ih264a_aligned_free(void *pv_ctxt, void *pv_buf)
{
    (void)pv_ctxt;
    free(pv_buf);
    return;
}
#endif
/*****************************************************************************/
/*                                                                           */
/*  Function Name : set_degrade                                 */
/*                                                                           */
/*  Description   : Control call to set degrade level       */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj  - Codec Handle                                */
/*                  type - degrade level value between 0 to 4                */
/*                    0 : No degrade                                         */
/*                    1st bit : Disable SAO                                  */
/*                    2nd bit : Disable Deblock                              */
/*                    3rd bit : Faster MC for non-ref                        */
/*                    4th bit : Fastest MC for non-ref                       */
/*                  pics - Pictures that are are degraded                    */
/*                    0 : No degrade                                         */
/*                    1 : Non-ref pictures                                   */
/*                    2 : Pictures at given interval are not degraded        */
/*                    3 : All non-key pictures                               */
/*                    4 : All pictures                                       */
/*  Globals       :                                                          */
/*  Processing    : Calls degrade control to the codec                       */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T set_degrade(void *codec_obj, UWORD32 type, WORD32 pics)
{
    ih264d_ctl_degrade_ip_t s_ctl_ip;
    ih264d_ctl_degrade_op_t s_ctl_op;
    void *pv_api_ip, *pv_api_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_ctl_ip.u4_size = sizeof(ih264d_ctl_degrade_ip_t);
    s_ctl_ip.i4_degrade_type = type;
    s_ctl_ip.i4_nondegrade_interval = 4;
    s_ctl_ip.i4_degrade_pics = pics;

    s_ctl_op.u4_size = sizeof(ih264d_ctl_degrade_op_t);

    pv_api_ip = (void *)&s_ctl_ip;
    pv_api_op = (void *)&s_ctl_op;

    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_ip.e_sub_cmd = (IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_DEGRADE;

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, pv_api_ip, pv_api_op);

    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in setting degrade level \n");
    }
    return (e_dec_status);

}



/*****************************************************************************/
/*                                                                           */
/*  Function Name : enable_skipb_frames                                      */
/*                                                                           */
/*  Description   : Control call to enable skipping of b frames              */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec handle                                 */
/*  Globals       :                                                          */
/*  Processing    : Calls enable skip B frames control                       */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T enable_skipb_frames(void *codec_obj,
                                         vid_dec_ctx_t *ps_app_ctx)
{
    ivd_ctl_set_config_ip_t s_ctl_ip;
    ivd_ctl_set_config_op_t s_ctl_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_ctl_ip.u4_disp_wd = ps_app_ctx->u4_strd;
    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_B;

    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                        (void *)&s_ctl_op);

    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in Enable SkipB frames \n");
    }

    return e_dec_status;
}
/*****************************************************************************/
/*                                                                           */
/*  Function Name : disable_skipb_frames                                     */
/*                                                                           */
/*  Description   : Control call to disable skipping of b frames             */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec handle                                 */
/*  Globals       :                                                          */
/*  Processing    : Calls disable B frame skip control                       */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T disable_skipb_frames(void *codec_obj,
                                          vid_dec_ctx_t *ps_app_ctx)
{
    ivd_ctl_set_config_ip_t s_ctl_ip;
    ivd_ctl_set_config_op_t s_ctl_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_ctl_ip.u4_disp_wd = ps_app_ctx->u4_strd;
    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;

    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                        (void *)&s_ctl_op);

    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in Disable SkipB frames\n");
    }

    return e_dec_status;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : enable_skippb_frames                                     */
/*                                                                           */
/*  Description   : Control call to enable skipping of P & B frames          */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec handle                                 */
/*  Globals       :                                                          */
/*  Processing    : Calls enable skip P and B frames control                 */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T enable_skippb_frames(void *codec_obj,
                                          vid_dec_ctx_t *ps_app_ctx)
{
    ivd_ctl_set_config_ip_t s_ctl_ip;
    ivd_ctl_set_config_op_t s_ctl_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_ctl_ip.u4_disp_wd = ps_app_ctx->u4_strd;
    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_PB;

    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                        (void *)&s_ctl_op);
    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in Enable SkipPB frames\n");
    }

    return e_dec_status;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : disable_skippb_frames                                    */
/*                                                                           */
/*  Description   : Control call to disable skipping of P and B frames       */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec handle                                 */
/*  Globals       :                                                          */
/*  Processing    : Calls disable P and B frame skip control                 */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T disable_skippb_frames(void *codec_obj,
                                           vid_dec_ctx_t *ps_app_ctx)
{
    ivd_ctl_set_config_ip_t s_ctl_ip;
    ivd_ctl_set_config_op_t s_ctl_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_ctl_ip.u4_disp_wd = ps_app_ctx->u4_strd;
    s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;

    s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                        (void *)&s_ctl_op);
    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in Disable SkipPB frames\n");
    }

    return e_dec_status;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : release_disp_frame                                       */
/*                                                                           */
/*  Description   : Calls release display control - Used to signal to the    */
/*                  decoder that this particular buffer has been displayed   */
/*                  and that the codec is now free to write to this buffer   */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec Handle                                 */
/*                  buf_id    : Buffer Id of the buffer to be released       */
/*                              This id would have been returned earlier by  */
/*                              the codec                                    */
/*  Globals       :                                                          */
/*  Processing    : Calls Release Display call                               */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Status of release display call                           */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T release_disp_frame(void *codec_obj, UWORD32 buf_id)
{
    ivd_rel_display_frame_ip_t s_video_rel_disp_ip;
    ivd_rel_display_frame_op_t s_video_rel_disp_op;
    IV_API_CALL_STATUS_T e_dec_status;

    s_video_rel_disp_ip.e_cmd = IVD_CMD_REL_DISPLAY_FRAME;
    s_video_rel_disp_ip.u4_size = sizeof(ivd_rel_display_frame_ip_t);
    s_video_rel_disp_op.u4_size = sizeof(ivd_rel_display_frame_op_t);
    s_video_rel_disp_ip.u4_disp_buf_id = buf_id;

    e_dec_status = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_video_rel_disp_ip,
                                        (void *)&s_video_rel_disp_op);
    if(IV_SUCCESS != e_dec_status)
    {
        printf("Error in Release Disp frame\n");
    }


    return (e_dec_status);
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : get_version                                      */
/*                                                                           */
/*  Description   : Control call to get codec version              */
/*                                                                           */
/*                                                                           */
/*  Inputs        : codec_obj : Codec handle                                 */
/*  Globals       :                                                          */
/*  Processing    : Calls enable skip B frames control                       */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : Control call return i4_status                               */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

IV_API_CALL_STATUS_T get_version(void *codec_obj)
{
    ivd_ctl_getversioninfo_ip_t ps_ctl_ip;
    ivd_ctl_getversioninfo_op_t ps_ctl_op;
    UWORD8 au1_buf[512];
    IV_API_CALL_STATUS_T i4_status;
    ps_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    ps_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
    ps_ctl_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
    ps_ctl_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
    ps_ctl_ip.pv_version_buffer = au1_buf;
    ps_ctl_ip.u4_version_buffer_size = sizeof(au1_buf);

    i4_status = ivd_api_function((iv_obj_t *)codec_obj,
                                     (void *)&(ps_ctl_ip),
                                     (void *)&(ps_ctl_op));

    if(i4_status != IV_SUCCESS)
    {
        printf("Error in Getting Version number e_dec_status = %d u4_error_code = %x\n",
                     i4_status, ps_ctl_op.u4_error_code);
    }
    else
    {
        printf("Ittiam Decoder Version number: %s\n",
              (char *)ps_ctl_ip.pv_version_buffer);
    }
    return i4_status;
}
/*****************************************************************************/
/*                                                                           */
/*  Function Name : codec_exit                                               */
/*                                                                           */
/*  Description   : handles unrecoverable errors                             */
/*  Inputs        : Error message                                            */
/*  Globals       : None                                                     */
/*  Processing    : Prints error message to console and exits.               */
/*  Outputs       : Error mesage to the console                              */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         07 06 2006   Sankar          Creation                             */
/*                                                                           */
/*****************************************************************************/
void codec_exit(CHAR *pc_err_message)
{
    printf("%s\n", pc_err_message);
    exit(-1);
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : dump_output                                              */
/*                                                                           */
/*  Description   : Used to dump output YUV                                  */
/*  Inputs        : App context, disp output desc, File pointer              */
/*  Globals       : None                                                     */
/*  Processing    : Dumps to a file                                          */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes (Describe the changes made)  */
/*         07 06 2006   Sankar          Creation                             */
/*                                                                           */
/*****************************************************************************/
void dump_output(vid_dec_ctx_t *ps_app_ctx,
                 iv_yuv_buf_t *ps_disp_frm_buf,
                 UWORD32 u4_disp_frm_id,
                 FILE *ps_op_file,
                 FILE *ps_op_chksum_file,
                 WORD32 i4_op_frm_ts,
                 UWORD32 file_save,
                 UWORD32 chksum_save)

{

    UWORD32 i;
    iv_yuv_buf_t s_dump_disp_frm_buf;
    UWORD32 u4_disp_id;

    memset(&s_dump_disp_frm_buf, 0, sizeof(iv_yuv_buf_t));

    if(ps_app_ctx->u4_share_disp_buf)
    {
        if(ps_app_ctx->dump_q_wr_idx == MAX_DISP_BUFFERS)
            ps_app_ctx->dump_q_wr_idx = 0;

        if(ps_app_ctx->dump_q_rd_idx == MAX_DISP_BUFFERS)
            ps_app_ctx->dump_q_rd_idx = 0;

        ps_app_ctx->s_disp_frm_queue[ps_app_ctx->dump_q_wr_idx] =
                        *ps_disp_frm_buf;
        ps_app_ctx->s_disp_frm_id_queue[ps_app_ctx->dump_q_wr_idx] =
                        u4_disp_frm_id;
        ps_app_ctx->dump_q_wr_idx++;

        if((WORD32)i4_op_frm_ts >= (WORD32)(ps_app_ctx->disp_delay - 1))
        {
            s_dump_disp_frm_buf =
                            ps_app_ctx->s_disp_frm_queue[ps_app_ctx->dump_q_rd_idx];
            u4_disp_id =
                            ps_app_ctx->s_disp_frm_id_queue[ps_app_ctx->dump_q_rd_idx];
            ps_app_ctx->dump_q_rd_idx++;
        }
        else
        {
            return;
        }
    }
    else
    {
        s_dump_disp_frm_buf = *ps_disp_frm_buf;
        u4_disp_id = u4_disp_frm_id;
    }

    release_disp_frame(ps_app_ctx->cocodec_obj, u4_disp_id);

    if(0 == file_save && 0 == chksum_save)
        return;

    if(NULL == s_dump_disp_frm_buf.pv_y_buf)
        return;

    if(ps_app_ctx->e_output_chroma_format == IV_YUV_420P)
    {
#if DUMP_SINGLE_BUF
        {
            UWORD8 *buf = s_dump_disp_frm_buf.pv_y_buf - 80 - (s_dump_disp_frm_buf.u4_y_strd * 80);

            UWORD32 i4_size = s_dump_disp_frm_buf.u4_y_strd * ((s_dump_disp_frm_buf.u4_y_ht + 160) + (s_dump_disp_frm_buf.u4_u_ht + 80));
            fwrite(buf, 1, i4_size ,ps_op_file);

        }
#else
        if(0 != file_save)
        {
            UWORD8 *buf;


            buf = (UWORD8 *)s_dump_disp_frm_buf.pv_y_buf;
            for(i = 0; i < s_dump_disp_frm_buf.u4_y_ht; i++)
            {
                fwrite(buf, 1, s_dump_disp_frm_buf.u4_y_wd, ps_op_file);
                buf += s_dump_disp_frm_buf.u4_y_strd;
            }

            buf = (UWORD8 *)s_dump_disp_frm_buf.pv_u_buf;
            for(i = 0; i < s_dump_disp_frm_buf.u4_u_ht; i++)
            {
                fwrite(buf, 1, s_dump_disp_frm_buf.u4_u_wd, ps_op_file);
                buf += s_dump_disp_frm_buf.u4_u_strd;
            }
            buf = (UWORD8 *)s_dump_disp_frm_buf.pv_v_buf;
            for(i = 0; i < s_dump_disp_frm_buf.u4_v_ht; i++)
            {
                fwrite(buf, 1, s_dump_disp_frm_buf.u4_v_wd, ps_op_file);
                buf += s_dump_disp_frm_buf.u4_v_strd;
            }

        }

        if(0 != chksum_save)
        {
            UWORD8 au1_y_chksum[16];
            UWORD8 au1_u_chksum[16];
            UWORD8 au1_v_chksum[16];
            calc_md5_cksum((UWORD8 *)s_dump_disp_frm_buf.pv_y_buf,
                           s_dump_disp_frm_buf.u4_y_strd,
                           s_dump_disp_frm_buf.u4_y_wd,
                           s_dump_disp_frm_buf.u4_y_ht,
                           au1_y_chksum);
            calc_md5_cksum((UWORD8 *)s_dump_disp_frm_buf.pv_u_buf,
                           s_dump_disp_frm_buf.u4_u_strd,
                           s_dump_disp_frm_buf.u4_u_wd,
                           s_dump_disp_frm_buf.u4_u_ht,
                           au1_u_chksum);
            calc_md5_cksum((UWORD8 *)s_dump_disp_frm_buf.pv_v_buf,
                           s_dump_disp_frm_buf.u4_v_strd,
                           s_dump_disp_frm_buf.u4_v_wd,
                           s_dump_disp_frm_buf.u4_v_ht,
                           au1_v_chksum);

            fwrite(au1_y_chksum, sizeof(UWORD8), 16, ps_op_chksum_file);
            fwrite(au1_u_chksum, sizeof(UWORD8), 16, ps_op_chksum_file);
            fwrite(au1_v_chksum, sizeof(UWORD8), 16, ps_op_chksum_file);
        }
#endif
    }
    else if((ps_app_ctx->e_output_chroma_format == IV_YUV_420SP_UV)
                    || (ps_app_ctx->e_output_chroma_format == IV_YUV_420SP_VU))
    {
#if DUMP_SINGLE_BUF
        {

            UWORD8 *buf = s_dump_disp_frm_buf.pv_y_buf - 24 - (s_dump_disp_frm_buf.u4_y_strd * 40);

            UWORD32 i4_size = s_dump_disp_frm_buf.u4_y_strd * ((s_dump_disp_frm_buf.u4_y_ht + 80) + (s_dump_disp_frm_buf.u4_u_ht + 40));
            fwrite(buf, 1, i4_size ,ps_op_file);
        }
#else
        {
            UWORD8 *buf;

            buf = (UWORD8 *)s_dump_disp_frm_buf.pv_y_buf;
            for(i = 0; i < s_dump_disp_frm_buf.u4_y_ht; i++)
            {
                fwrite(buf, 1, s_dump_disp_frm_buf.u4_y_wd, ps_op_file);
                buf += s_dump_disp_frm_buf.u4_y_strd;
            }

            buf = (UWORD8 *)s_dump_disp_frm_buf.pv_u_buf;
            for(i = 0; i < s_dump_disp_frm_buf.u4_u_ht; i++)
            {
                fwrite(buf, 1, s_dump_disp_frm_buf.u4_u_wd, ps_op_file);
                buf += s_dump_disp_frm_buf.u4_u_strd;
            }
        }
#endif
    }
    else if(ps_app_ctx->e_output_chroma_format == IV_RGBA_8888)
    {
        UWORD8 *buf;

        buf = (UWORD8 *)s_dump_disp_frm_buf.pv_y_buf;
        for(i = 0; i < s_dump_disp_frm_buf.u4_y_ht; i++)
        {
            fwrite(buf, 1, s_dump_disp_frm_buf.u4_y_wd * 4, ps_op_file);
            buf += s_dump_disp_frm_buf.u4_y_strd * 4;
        }
    }
    else
    {
        UWORD8 *buf;

        buf = (UWORD8 *)s_dump_disp_frm_buf.pv_y_buf;
        for(i = 0; i < s_dump_disp_frm_buf.u4_y_ht; i++)
        {
            fwrite(buf, 1, s_dump_disp_frm_buf.u4_y_strd * 2, ps_op_file);
            buf += s_dump_disp_frm_buf.u4_y_strd * 2;
        }
    }

    fflush(ps_op_file);
    fflush(ps_op_chksum_file);

}


/*****************************************************************************/
/*                                                                           */
/*  Function Name : print_usage                                              */
/*                                                                           */
/*  Description   : Prints argument format                                   */
/*                                                                           */
/*                                                                           */
/*  Inputs        :                                                          */
/*  Globals       :                                                          */
/*  Processing    : Prints argument format                                   */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

void print_usage(void)
{
    WORD32 i = 0;
    WORD32 num_entries = sizeof(argument_mapping) / sizeof(argument_t);
    printf("\nUsage:\n");
    while(i < num_entries)
    {
        printf("%-32s\t %s", argument_mapping[i].argument_name,
               argument_mapping[i].description);
        i++;
    }
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : get_argument                                             */
/*                                                                           */
/*  Description   : Gets argument for a given string                         */
/*                                                                           */
/*                                                                           */
/*  Inputs        : name                                                     */
/*  Globals       :                                                          */
/*  Processing    : Searches the given string in the array and returns       */
/*                  appropriate argument ID                                  */
/*                                                                           */
/*  Outputs       : Argument ID                                              */
/*  Returns       : Argument ID                                              */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

ARGUMENT_T get_argument(CHAR *name)
{
    WORD32 i = 0;
    WORD32 num_entries = sizeof(argument_mapping) / sizeof(argument_t);
    while(i < num_entries)
    {
        if((0 == strcmp(argument_mapping[i].argument_name, name))       ||
          ((0 == strcmp(argument_mapping[i].argument_shortname, name))  &&
           (0 != strcmp(argument_mapping[i].argument_shortname, "--"))))
        {
            return argument_mapping[i].argument;
        }
        i++;
    }
    return INVALID;
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : get_argument                                             */
/*                                                                           */
/*  Description   : Gets argument for a given string                         */
/*                                                                           */
/*                                                                           */
/*  Inputs        : name                                                     */
/*  Globals       :                                                          */
/*  Processing    : Searches the given string in the array and returns       */
/*                  appropriate argument ID                                  */
/*                                                                           */
/*  Outputs       : Argument ID                                              */
/*  Returns       : Argument ID                                              */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

void parse_argument(vid_dec_ctx_t *ps_app_ctx, CHAR *argument, CHAR *value)
{
    ARGUMENT_T arg;

    arg = get_argument(argument);
    switch(arg)
    {
        case HELP:
            print_usage();
            exit(-1);
        case VERSION:
            break;
        case INPUT_FILE:
            sscanf(value, "%s", ps_app_ctx->ac_ip_fname);
            //input_passed = 1;
            break;

        case OUTPUT:
            sscanf(value, "%s", ps_app_ctx->ac_op_fname);
            break;

        case CHKSUM:
            sscanf(value, "%s", ps_app_ctx->ac_op_chksum_fname);
            break;

        case SAVE_OUTPUT:
            sscanf(value, "%d", &ps_app_ctx->u4_file_save_flag);
            break;

        case SAVE_CHKSUM:
            sscanf(value, "%d", &ps_app_ctx->u4_chksum_save_flag);
            break;

        case CHROMA_FORMAT:
            if((strcmp(value, "YUV_420P")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_YUV_420P;
            else if((strcmp(value, "YUV_422ILE")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_YUV_422ILE;
            else if((strcmp(value, "RGB_565")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_RGB_565;
            else if((strcmp(value, "RGBA_8888")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_RGBA_8888;
            else if((strcmp(value, "YUV_420SP_UV")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_YUV_420SP_UV;
            else if((strcmp(value, "YUV_420SP_VU")) == 0)
                ps_app_ctx->e_output_chroma_format = IV_YUV_420SP_VU;
            else
            {
                printf("\nInvalid colour format setting it to IV_YUV_420P\n");
                ps_app_ctx->e_output_chroma_format = IV_YUV_420P;
            }

            break;
        case NUM_FRAMES:
            sscanf(value, "%d", &ps_app_ctx->u4_max_frm_ts);
            break;

        case NUM_CORES:
            sscanf(value, "%d", &ps_app_ctx->u4_num_cores);
            break;
        case DEGRADE_PICS:
            sscanf(value, "%d", &ps_app_ctx->i4_degrade_pics);
            break;
        case DEGRADE_TYPE:
            sscanf(value, "%d", &ps_app_ctx->i4_degrade_type);
            break;
        case SHARE_DISPLAY_BUF:
            sscanf(value, "%d", &ps_app_ctx->u4_share_disp_buf);
            break;
        case LOOPBACK:
            sscanf(value, "%d", &ps_app_ctx->loopback);
            break;
        case DISPLAY:
#if defined(SDL_DISPLAY) || defined(FBDEV_DISPLAY) || defined(INTEL_CE5300) || defined(IOS_DISPLAY)
            sscanf(value, "%d", &ps_app_ctx->display);
#else
            ps_app_ctx->display = 0;
#endif
            break;
        case FULLSCREEN:
            sscanf(value, "%d", &ps_app_ctx->full_screen);
            break;
        case FPS:
            sscanf(value, "%d", &ps_app_ctx->fps);
            if(ps_app_ctx->fps <= 0)
                ps_app_ctx->fps = DEFAULT_FPS;
            break;
        case ARCH:
            if((strcmp(value, "ARM_NONEON")) == 0)
                ps_app_ctx->e_arch = ARCH_ARM_NONEON;
            else if((strcmp(value, "ARM_A9Q")) == 0)
                ps_app_ctx->e_arch = ARCH_ARM_A9Q;
            else if((strcmp(value, "ARM_A7")) == 0)
                ps_app_ctx->e_arch = ARCH_ARM_A7;
            else if((strcmp(value, "ARM_A5")) == 0)
                ps_app_ctx->e_arch = ARCH_ARM_A5;
            else if((strcmp(value, "ARM_NEONINTR")) == 0)
                ps_app_ctx->e_arch = ARCH_ARM_NEONINTR;
            else if((strcmp(value, "X86_GENERIC")) == 0)
                ps_app_ctx->e_arch = ARCH_X86_GENERIC;
            else if((strcmp(value, "X86_SSSE3")) == 0)
                ps_app_ctx->e_arch = ARCH_X86_SSSE3;
            else if((strcmp(value, "X86_SSE42")) == 0)
                ps_app_ctx->e_arch = ARCH_X86_SSE42;
            else if((strcmp(value, "X86_AVX2")) == 0)
                ps_app_ctx->e_arch = ARCH_X86_AVX2;
            else if((strcmp(value, "MIPS_GENERIC")) == 0)
                ps_app_ctx->e_arch = ARCH_MIPS_GENERIC;
            else if((strcmp(value, "MIPS_32")) == 0)
                ps_app_ctx->e_arch = ARCH_MIPS_32;
            else if((strcmp(value, "ARMV8_GENERIC")) == 0)
                ps_app_ctx->e_arch = ARCH_ARMV8_GENERIC;
            else
            {
                printf("\nInvalid Arch. Setting it to ARM_A9Q\n");
                ps_app_ctx->e_arch = ARCH_ARM_A9Q;
            }

            break;
        case SOC:
            if((strcmp(value, "GENERIC")) == 0)
                ps_app_ctx->e_soc = SOC_GENERIC;
            else if((strcmp(value, "HISI_37X")) == 0)
                ps_app_ctx->e_soc = SOC_HISI_37X;
            else
            {
                ps_app_ctx->e_soc = atoi(value);
/*
                printf("\nInvalid SOC. Setting it to GENERIC\n");
                ps_app_ctx->e_soc = SOC_GENERIC;
*/
            }
            break;
        case PICLEN:
            sscanf(value, "%d", &ps_app_ctx->u4_piclen_flag);
            break;

        case PICLEN_FILE:
            sscanf(value, "%s", ps_app_ctx->ac_piclen_fname);
            break;
        case DISABLE_DEBLOCK_LEVEL:
            sscanf(value, "%d", &ps_app_ctx->u4_disable_dblk_level);
            break;

        case INVALID:
        default:
            printf("Ignoring argument :  %s\n", argument);
            break;
    }
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : read_cfg_file                                            */
/*                                                                           */
/*  Description   : Reads arguments from a configuration file                */
/*                                                                           */
/*                                                                           */
/*  Inputs        : ps_app_ctx  : Application context                        */
/*                  fp_cfg_file : Configuration file handle                  */
/*  Globals       :                                                          */
/*  Processing    : Parses the arguments and fills in the application context*/
/*                                                                           */
/*  Outputs       : Arguments parsed                                         */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        :                                                          */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

void read_cfg_file(vid_dec_ctx_t *ps_app_ctx, FILE *fp_cfg_file)
{

    CHAR line[STRLENGTH];
    CHAR description[STRLENGTH];
    CHAR value[STRLENGTH];
    CHAR argument[STRLENGTH];
    void *ret;
    while(0 == feof(fp_cfg_file))
    {
        line[0] = '\0';
        ret = fgets(line, STRLENGTH, fp_cfg_file);
        if(NULL == ret)
            break;
        argument[0] = '\0';
        /* Reading Input File Name */
        sscanf(line, "%s %s %s", argument, value, description);
        if(argument[0] == '\0')
            continue;

        parse_argument(ps_app_ctx, argument, value);
    }


}

/*!
**************************************************************************
* \if Function name : dispq_producer_dequeue \endif
*
* \brief
*    This function gets a free buffer index where display data can be written
*    This is a blocking call and can be exited by setting quit to true in
*    the application context
*
* \param[in]  ps_app_ctx  : Pointer to application context
*
* \return
*    returns Next free buffer index for producer
*
* \author
*  Ittiam
*
**************************************************************************
*/
WORD32 dispq_producer_dequeue(vid_dec_ctx_t *ps_app_ctx)
{
    WORD32 idx;

    /* If there is no free buffer wait */

    while(((ps_app_ctx->disp_q_wr_idx + 1) % NUM_DISPLAY_BUFFERS) == ps_app_ctx->disp_q_rd_idx)
    {

        ithread_msleep(1);

        if(ps_app_ctx->quit)
            return(-1);
    }

    idx = ps_app_ctx->disp_q_wr_idx;
    return (idx);
}

/*!
**************************************************************************
* \if Function name : dispq_producer_queue \endif
*
* \brief
*    This function adds buffer which can be displayed
*
* \param[in]  ps_app_ctx  : Pointer to application context
*
* \return
*    returns Next free buffer index for producer
*
* \author
*  Ittiam
*
**************************************************************************
*/
WORD32 dispq_producer_queue(vid_dec_ctx_t *ps_app_ctx)
{
    ps_app_ctx->disp_q_wr_idx++;
    if(ps_app_ctx->disp_q_wr_idx == NUM_DISPLAY_BUFFERS)
        ps_app_ctx->disp_q_wr_idx = 0;

    return (0);
}
/*!
**************************************************************************
* \if Function name : dispq_consumer_dequeue \endif
*
* \brief
*    This function gets a free buffer index where display data can be written
*    This is a blocking call and can be exited by setting quit to true in
*    the application context
*
* \param[in]  ps_app_ctx  : Pointer to application context
*
* \return
*    returns Next free buffer index for producer
*
* \author
*  Ittiam
*
**************************************************************************
*/
WORD32 dispq_consumer_dequeue(vid_dec_ctx_t *ps_app_ctx)
{
    WORD32 idx;

    /* If there is no free buffer wait */

    while(ps_app_ctx->disp_q_wr_idx == ps_app_ctx->disp_q_rd_idx)
    {

        ithread_msleep(1);

        if(ps_app_ctx->quit)
            return(-1);
    }

    idx = ps_app_ctx->disp_q_rd_idx;
    return (idx);
}

/*!
**************************************************************************
* \if Function name : dispq_producer_queue \endif
*
* \brief
*    This function adds buffer which can be displayed
*
* \param[in]  ps_app_ctx  : Pointer to application context
*
* \return
*    returns Next free buffer index for producer
*
* \author
*  Ittiam
*
**************************************************************************
*/
WORD32 dispq_consumer_queue(vid_dec_ctx_t *ps_app_ctx)
{
    ps_app_ctx->disp_q_rd_idx++;
    if(ps_app_ctx->disp_q_rd_idx == NUM_DISPLAY_BUFFERS)
        ps_app_ctx->disp_q_rd_idx = 0;

    return (0);
}

/*****************************************************************************/
/*                                                                           */
/*  Function Name : display_thread                                           */
/*                                                                           */
/*  Description   : Thread to display the frame                              */
/*                                                                           */
/*                                                                           */
/*  Inputs        : pv_ctx  : Application context                            */
/*                                                                           */
/*  Globals       :                                                          */
/*  Processing    : Wait for a buffer to get produced by decoder and display */
/*                  that frame                                               */
/*                                                                           */
/*  Outputs       :                                                          */
/*  Returns       : None                                                     */
/*                                                                           */
/*  Issues        : Pause followed by quit is making some deadlock condn     */
/*                  If decoder was lagging initially and then fasten up,     */
/*                  display will also go at faster rate till it reaches      */
/*                  equilibrium wrt the initial time                         */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 05 2013   100578          Initial Version                      */
/*                                                                           */
/*****************************************************************************/

WORD32 display_thread(void *pv_ctx)
{
    vid_dec_ctx_t *ps_app_ctx = (vid_dec_ctx_t *) pv_ctx;


    UWORD32 frm_duration; /* in us */
    UWORD32 current_time;
    UWORD32 expected_time;
    TIMER   s_end_timer;
    TIMER   s_first_frame_time;
    UWORD32 first_frame_displayed;

#ifdef WINDOWS_TIMER
    TIMER frequency;
#endif

#ifdef WINDOWS_TIMER
        QueryPerformanceFrequency ( &frequency);
#endif
    first_frame_displayed = 0;
    expected_time = 0;
    frm_duration = 1000000/ps_app_ctx->fps;

    /* Init display and allocate display buffers */
    ps_app_ctx->pv_disp_ctx = (void *)ps_app_ctx->disp_init(ps_app_ctx->u4_pic_wd,
                                                            ps_app_ctx->u4_pic_ht,
                                                            ps_app_ctx->i4_screen_wd,
                                                            ps_app_ctx->i4_screen_ht,
                                                            ps_app_ctx->u4_pic_wd,
                                                            ps_app_ctx->u4_pic_ht,
                                                            ps_app_ctx->full_screen,
                                                            &ps_app_ctx->quit,
                                                            &ps_app_ctx->paused);
    ps_app_ctx->alloc_disp_buffers(ps_app_ctx->pv_disp_ctx);

    ps_app_ctx->display_init_done = 1;

    while(1)
    {
        WORD32 rd_idx;

        rd_idx = dispq_consumer_dequeue(ps_app_ctx);
        if (ps_app_ctx->quit)
                break;

        ps_app_ctx->display_buffer(ps_app_ctx->pv_disp_ctx, rd_idx);

        if(0 == first_frame_displayed)
        {
            GETTIME(&s_first_frame_time);
            first_frame_displayed = 1;
        }

        /*********************************************************************/
        /* Sleep based on the expected time of arrival of current buffer and */
        /* the Current frame                                                 */
        /*********************************************************************/

        GETTIME(&s_end_timer);
        ELAPSEDTIME(s_first_frame_time,s_end_timer,current_time,frequency);

        /* time in micro second */
        expected_time += frm_duration;

        //printf("current_time %d expected_time %d diff %d \n", current_time, expected_time, (expected_time - current_time));
        /* sleep for the diff. in time */
        if(current_time < expected_time)
            ps_app_ctx->disp_usleep((expected_time - current_time));
        else
            expected_time += (current_time - expected_time);

        dispq_consumer_queue(ps_app_ctx);

    }


    while(0 == ps_app_ctx->display_deinit_flag)
    {
        ps_app_ctx->disp_usleep(1000);
    }
    ps_app_ctx->disp_deinit(ps_app_ctx->pv_disp_ctx);

    return 0;
}

void output_write_stall(CHAR *fname, UWORD32 cur_frm_idx)
{
    const UWORD8 threshold = 64;
    CHAR past_fname[1000];
    FILE *fp_fast_file = NULL;

    if (cur_frm_idx >= threshold)
    {
        sprintf(past_fname, fname, cur_frm_idx - threshold);
        do
        {
            fp_fast_file = fopen(past_fname,"rb");
            if (fp_fast_file != NULL)
            {
                fclose(fp_fast_file);
                /* Wait until the resource is released by a third party app*/
                ithread_msleep(5);
            }
            else
                break;
        } while(1);
    }
}

void flush_output(iv_obj_t *codec_obj,
                  vid_dec_ctx_t *ps_app_ctx,
                  ivd_out_bufdesc_t *ps_out_buf,
                  UWORD8 *pu1_bs_buf,
                  UWORD32 *pu4_op_frm_ts,
                  FILE *ps_op_file,
                  FILE *ps_op_chksum_file,
                  UWORD32 u4_ip_frm_ts,
                  UWORD32 u4_bytes_remaining)
{
    WORD32 ret;

    do
    {

        ivd_ctl_flush_ip_t s_ctl_ip;
        ivd_ctl_flush_op_t s_ctl_op;

        if(*pu4_op_frm_ts >= (ps_app_ctx->u4_max_frm_ts + ps_app_ctx->disp_delay))
            break;

        s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
        s_ctl_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
        s_ctl_op.u4_size = sizeof(ivd_ctl_flush_op_t);
        ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                   (void *)&s_ctl_op);

        if(ret != IV_SUCCESS)
        {
            printf("Error in Setting the decoder in flush mode\n");
        }

        if(IV_SUCCESS == ret)
        {
            ivd_video_decode_ip_t s_video_decode_ip;
            ivd_video_decode_op_t s_video_decode_op;

            s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
            s_video_decode_ip.u4_ts = u4_ip_frm_ts;
            s_video_decode_ip.pv_stream_buffer = pu1_bs_buf;
            s_video_decode_ip.u4_num_Bytes = u4_bytes_remaining;
            s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t);
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[0] =
                            ps_out_buf->u4_min_out_buf_size[0];
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] =
                            ps_out_buf->u4_min_out_buf_size[1];
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[2] =
                            ps_out_buf->u4_min_out_buf_size[2];

            s_video_decode_ip.s_out_buffer.pu1_bufs[0] =
                            ps_out_buf->pu1_bufs[0];
            s_video_decode_ip.s_out_buffer.pu1_bufs[1] =
                            ps_out_buf->pu1_bufs[1];
            s_video_decode_ip.s_out_buffer.pu1_bufs[2] =
                            ps_out_buf->pu1_bufs[2];
            s_video_decode_ip.s_out_buffer.u4_num_bufs =
                            ps_out_buf->u4_num_bufs;

            s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t);

            /*****************************************************************************/
            /*   API Call: Video Decode                                                  */
            /*****************************************************************************/
            ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_video_decode_ip,
                                       (void *)&s_video_decode_op);

            if(1 == s_video_decode_op.u4_output_present)
            {
                CHAR cur_fname[1000];
                CHAR *extn = NULL;
                /* The objective is to dump the decoded frames into separate files instead of
                 * dumping all the frames in one common file. Also, the number of dumped frames
                 * at any given instance of time cannot exceed 'frame_memory'
                 */
                if(ps_app_ctx->u4_file_save_flag)
                {
                    /* Locate the position of extension yuv */
                    extn = strstr(ps_app_ctx->ac_op_fname,"%d");
                    if (extn != NULL)
                    {
                        output_write_stall(ps_app_ctx->ac_op_fname,*pu4_op_frm_ts);
                        /* Generate output file names */
                        sprintf(cur_fname,ps_app_ctx->ac_op_fname,*pu4_op_frm_ts);
                        /* Open Output file */
                        ps_op_file = fopen(cur_fname,"wb");
                        if (NULL == ps_op_file)
                        {
                            CHAR ac_error_str[STRLENGTH];
                            sprintf(ac_error_str, "Could not open output file %s",
                                    cur_fname);

                            codec_exit(ac_error_str);
                        }
                    }
                }

                dump_output(ps_app_ctx, &(s_video_decode_op.s_disp_frm_buf),
                            s_video_decode_op.u4_disp_buf_id, ps_op_file,
                            ps_op_chksum_file,
                            *pu4_op_frm_ts, ps_app_ctx->u4_file_save_flag,
                            ps_app_ctx->u4_chksum_save_flag);
                if (extn != NULL)
                    fclose(ps_op_file);
                (*pu4_op_frm_ts)++;
            }
        }
    }
    while(IV_SUCCESS == ret);

}

#ifdef X86_MINGW
void sigsegv_handler()
{
    printf("Segmentation fault, Exiting.. \n");
    exit(-1);
}
#endif

UWORD32 default_get_stride(void)
{
    return 0;
}


IV_COLOR_FORMAT_T default_get_color_fmt(void)
{
    return IV_YUV_420P;
}
/*****************************************************************************/
/*                                                                           */
/*  Function Name : main                                                     */
/*                                                                           */
/*  Description   : Application to demonstrate codec API                     */
/*                                                                           */
/*                                                                           */
/*  Inputs        : argc    - Number of arguments                            */
/*                  argv[]  - Arguments                                      */
/*  Globals       :                                                          */
/*  Processing    : Shows how to use create, process, control and delete     */
/*                                                                           */
/*  Outputs       : Codec output in a file                                   */
/*  Returns       :                                                          */
/*                                                                           */
/*  Issues        : Assumes both PROFILE_ENABLE to be                        */
/*                  defined for multithread decode-display working           */
/*                                                                           */
/*  Revision History:                                                        */
/*                                                                           */
/*         DD MM YYYY   Author(s)       Changes                              */
/*         07 09 2012   100189          Initial Version                      */
/*         09 05 2013   100578          Multithread decode-display           */
/*****************************************************************************/
#ifdef IOS
int h264dec_main(char * homedir,char *documentdir, int screen_wd, int screen_ht)
#else
int main(WORD32 argc, CHAR *argv[])
#endif
{
    CHAR ac_cfg_fname[STRLENGTH];
    FILE *fp_cfg_file = NULL;
    FILE *ps_piclen_file = NULL;
    FILE *ps_ip_file = NULL;
    FILE *ps_op_file = NULL;
    FILE *ps_op_chksum_file = NULL;
    WORD32 ret;
    CHAR ac_error_str[STRLENGTH];
    vid_dec_ctx_t s_app_ctx;
    UWORD8 *pu1_bs_buf = NULL;

    ivd_out_bufdesc_t *ps_out_buf;
    UWORD32 u4_num_bytes_dec = 0;
    UWORD32 file_pos = 0;

    UWORD32 u4_ip_frm_ts = 0, u4_op_frm_ts = 0;

    WORD32 u4_bytes_remaining = 0;
    UWORD32 i;
    UWORD32 u4_ip_buf_len;
    UWORD32 frm_cnt = 0;
    WORD32 total_bytes_comsumed;
    UWORD32 max_op_frm_ts;
    UWORD32 u4_num_disp_bufs_with_dec;

#ifdef PROFILE_ENABLE
    UWORD32 u4_tot_cycles = 0;
    UWORD32 u4_tot_fmt_cycles = 0;
    UWORD32 peak_window[PEAK_WINDOW_SIZE];
    UWORD32 peak_window_idx = 0;
    UWORD32 peak_avg_max = 0;
#ifdef INTEL_CE5300
    UWORD32 time_consumed = 0;
    UWORD32 bytes_consumed = 0;
#endif
#endif

#ifdef WINDOWS_TIMER
    TIMER frequency;
#endif
    WORD32 width = 0, height = 0;
    iv_obj_t *codec_obj;
#if defined(GPU_BUILD) && !defined(X86)
//    int ioctl_init();
//    ioctl_init();
#endif

#ifdef X86_MINGW
    //For getting printfs without any delay
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
#endif
#ifdef IOS
        sprintf(filename_trace, "%s/iostrace.txt", homedir );
        printf("\ntrace file name = %s",filename_trace);
#endif

#ifdef X86_MINGW
    {
        signal(SIGSEGV, sigsegv_handler);
    }
#endif


#ifndef IOS
    /* Usage */
    if(argc < 2)
    {
        printf("Using test.cfg as configuration file \n");
        strcpy(ac_cfg_fname, "test.cfg");
    }
    else if(argc == 2)
    {
        strcpy(ac_cfg_fname, argv[1]);
    }

#else
    strcpy(ac_cfg_fname, "test.cfg");

#endif


    /***********************************************************************/
    /*                  Initialize Application parameters                  */
    /***********************************************************************/

    strcpy(s_app_ctx.ac_ip_fname, "\0");
    s_app_ctx.dump_q_wr_idx = 0;
    s_app_ctx.dump_q_rd_idx = 0;
    s_app_ctx.display_thread_created = 0;
    s_app_ctx.disp_q_wr_idx = 0;
    s_app_ctx.disp_q_rd_idx = 0;
    s_app_ctx.disp_delay = 0;
    s_app_ctx.loopback = 0;
    s_app_ctx.display = 0;
    s_app_ctx.full_screen = 0;
    s_app_ctx.u4_piclen_flag = 0;
    s_app_ctx.fps = DEFAULT_FPS;
    file_pos = 0;
    total_bytes_comsumed = 0;
    u4_ip_frm_ts = 0;
    u4_op_frm_ts = 0;
#ifdef PROFILE_ENABLE
    memset(peak_window, 0, sizeof(WORD32) * PEAK_WINDOW_SIZE);
#endif
    s_app_ctx.u4_share_disp_buf = DEFAULT_SHARE_DISPLAY_BUF;
    s_app_ctx.u4_num_cores = DEFAULT_NUM_CORES;
    s_app_ctx.i4_degrade_type = 0;
    s_app_ctx.i4_degrade_pics = 0;
    s_app_ctx.e_arch = ARCH_ARM_A9Q;
    s_app_ctx.e_soc = SOC_GENERIC;

    s_app_ctx.u4_strd = STRIDE;

    s_app_ctx.display_thread_handle           = malloc(ithread_get_handle_size());
    s_app_ctx.quit          = 0;
    s_app_ctx.paused        = 0;
    //s_app_ctx.u4_output_present = 0;

    s_app_ctx.get_stride = &default_get_stride;

    s_app_ctx.get_color_fmt = &default_get_color_fmt;

    /* Set function pointers for display */
#ifdef SDL_DISPLAY
    s_app_ctx.disp_init = &sdl_disp_init;
    s_app_ctx.alloc_disp_buffers = &sdl_alloc_disp_buffers;
    s_app_ctx.display_buffer = &sdl_display;
    s_app_ctx.set_disp_buffers = &sdl_set_disp_buffers;
    s_app_ctx.disp_deinit = &sdl_disp_deinit;
    s_app_ctx.disp_usleep = &sdl_disp_usleep;
    s_app_ctx.get_color_fmt = &sdl_get_color_fmt;
    s_app_ctx.get_stride = &sdl_get_stride;
#endif

#ifdef FBDEV_DISPLAY
    s_app_ctx.disp_init = &fbd_disp_init;
    s_app_ctx.alloc_disp_buffers = &fbd_alloc_disp_buffers;
    s_app_ctx.display_buffer = &fbd_display;
    s_app_ctx.set_disp_buffers = &fbd_set_disp_buffers;
    s_app_ctx.disp_deinit = &fbd_disp_deinit;
    s_app_ctx.disp_usleep = &fbd_disp_usleep;
    s_app_ctx.get_color_fmt = &fbd_get_color_fmt;
    s_app_ctx.get_stride = &fbd_get_stride;
#endif

#ifdef INTEL_CE5300
    s_app_ctx.disp_init = &gdl_disp_init;
    s_app_ctx.alloc_disp_buffers = &gdl_alloc_disp_buffers;
    s_app_ctx.display_buffer = &gdl_display;
    s_app_ctx.set_disp_buffers = &gdl_set_disp_buffers;
    s_app_ctx.disp_deinit = &gdl_disp_deinit;
    s_app_ctx.disp_usleep = &gdl_disp_usleep;
    s_app_ctx.get_color_fmt = &gdl_get_color_fmt;
    s_app_ctx.get_stride = &gdl_get_stride;
#endif

#ifdef IOS_DISPLAY
    s_app_ctx.disp_init = &ios_disp_init;
    s_app_ctx.alloc_disp_buffers = &ios_alloc_disp_buffers;
    s_app_ctx.display_buffer = &ios_display;
    s_app_ctx.set_disp_buffers = &ios_set_disp_buffers;
    s_app_ctx.disp_deinit = &ios_disp_deinit;
    s_app_ctx.disp_usleep = &ios_disp_usleep;
    s_app_ctx.get_color_fmt = &ios_get_color_fmt;
    s_app_ctx.get_stride = &ios_get_stride;
#endif

    s_app_ctx.display_deinit_flag = 0;
    s_app_ctx.e_output_chroma_format = IV_YUV_420SP_UV;
    /*************************************************************************/
    /* Parse arguments                                                       */
    /*************************************************************************/

#ifndef IOS
    /* Read command line arguments */
    if(argc > 2)
    {
        for(i = 1; i < (UWORD32)argc; i += 2)
        {
            if(CONFIG == get_argument(argv[i]))
            {
                strcpy(ac_cfg_fname, argv[i + 1]);
                if((fp_cfg_file = fopen(ac_cfg_fname, "r")) == NULL)
                {
                    sprintf(ac_error_str, "Could not open Configuration file %s",
                            ac_cfg_fname);
                    codec_exit(ac_error_str);
                }
                read_cfg_file(&s_app_ctx, fp_cfg_file);
                fclose(fp_cfg_file);
            }
            else
            {
                parse_argument(&s_app_ctx, argv[i], argv[i + 1]);
            }
        }
    }
    else
    {
        if((fp_cfg_file = fopen(ac_cfg_fname, "r")) == NULL)
        {
            sprintf(ac_error_str, "Could not open Configuration file %s",
                    ac_cfg_fname);
            codec_exit(ac_error_str);
        }
        read_cfg_file(&s_app_ctx, fp_cfg_file);
        fclose(fp_cfg_file);
    }
#else
    sprintf(filename_with_path, "%s/%s", homedir, ac_cfg_fname);
    if((fp_cfg_file = fopen(filename_with_path, "r")) == NULL)
    {
        sprintf(ac_error_str, "Could not open Configuration file %s",
                ac_cfg_fname);
        codec_exit(ac_error_str);

    }
    read_cfg_file(&s_app_ctx, fp_cfg_file);
    fclose(fp_cfg_file);

#endif
#ifdef PRINT_PICSIZE
    /* If the binary is used for only getting number of bytes in each picture, then disable the following features */
    s_app_ctx.u4_piclen_flag = 0;
    s_app_ctx.u4_file_save_flag = 0;
    s_app_ctx.u4_chksum_save_flag = 0;
    s_app_ctx.i4_degrade_pics = 0;
    s_app_ctx.i4_degrade_type = 0;
    s_app_ctx.loopback = 0;
    s_app_ctx.u4_share_disp_buf = 0;
    s_app_ctx.display = 0;
#endif

    /* If display is enabled, then turn off shared mode and get color format that is supported by display */
    if(1 == s_app_ctx.display)
    {
        s_app_ctx.u4_share_disp_buf = 0;
        s_app_ctx.e_output_chroma_format = s_app_ctx.get_color_fmt();
    }
    if(strcmp(s_app_ctx.ac_ip_fname, "\0") == 0)
    {
        printf("\nNo input file given for decoding\n");
        exit(-1);
    }



    /***********************************************************************/
    /*          create the file object for input file                      */
    /***********************************************************************/
#ifdef IOS
  sprintf(filename_with_path, "%s/%s", homedir, s_app_ctx.ac_ip_fname);
   ps_ip_file = fopen(filename_with_path, "rb");
#else
    ps_ip_file = fopen(s_app_ctx.ac_ip_fname, "rb");
#endif
    if(NULL == ps_ip_file)
    {
        sprintf(ac_error_str, "Could not open input file %s",
                s_app_ctx.ac_ip_fname);
        codec_exit(ac_error_str);
    }
    /***********************************************************************/
    /*          create the file object for input file                      */
    /***********************************************************************/
    if(1 == s_app_ctx.u4_piclen_flag)
    {
#ifdef IOS
        sprintf(filename_with_path, "%s/%s", homedir, s_app_ctx.ac_piclen_fname);
        ps_piclen_file = fopen(filename_with_path, "rb");
#else
        ps_piclen_file = fopen(s_app_ctx.ac_piclen_fname, "rb");
#endif
        if(NULL == ps_piclen_file)
        {
            sprintf(ac_error_str, "Could not open piclen file %s",
                s_app_ctx.ac_piclen_fname);
            codec_exit(ac_error_str);
        }
    }

    /***********************************************************************/
    /*          create the file object for output file                     */
    /***********************************************************************/

    /* If the filename does not contain %d, then output will be dumped to
       a single file and it is opened here */
    if((1 == s_app_ctx.u4_file_save_flag) && (strstr(s_app_ctx.ac_op_fname,"%d") == NULL))
    {
#ifdef IOS
    sprintf(filename_with_path, "%s/%s", documentdir, s_app_ctx.ac_op_fname);
    ps_op_file = fopen(filename_with_path,"wb");
#else
        ps_op_file = fopen(s_app_ctx.ac_op_fname, "wb");
#endif

        if(NULL == ps_op_file)
        {
            sprintf(ac_error_str, "Could not open output file %s",
                    s_app_ctx.ac_op_fname);
            codec_exit(ac_error_str);
        }
    }

    /***********************************************************************/
    /*          create the file object for check sum file                  */
    /***********************************************************************/
    if(1 == s_app_ctx.u4_chksum_save_flag)
    {
#if IOS
        sprintf(filename_with_path, "%s/%s", documentdir, s_app_ctx.ac_op_chksum_fname);
        ps_op_chksum_file = fopen(filename_with_path,"wb");
#else
        ps_op_chksum_file = fopen(s_app_ctx.ac_op_chksum_fname, "wb");
#endif
        if(NULL == ps_op_chksum_file)
        {
            sprintf(ac_error_str, "Could not open check sum file %s",
                    s_app_ctx.ac_op_chksum_fname);
            codec_exit(ac_error_str);
        }
    }
    /***********************************************************************/
    /*                      Create decoder instance                        */
    /***********************************************************************/
    {

        ps_out_buf = (ivd_out_bufdesc_t *)malloc(sizeof(ivd_out_bufdesc_t));

        /*****************************************************************************/
        /*   API Call: Initialize the Decoder                                        */
        /*****************************************************************************/
        {
            ih264d_create_ip_t s_create_ip;
            ih264d_create_op_t s_create_op;
            void *fxns = &ivd_api_function;

            s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
            s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = s_app_ctx.u4_share_disp_buf;
            s_create_ip.s_ivd_create_ip_t.e_output_format = (IV_COLOR_FORMAT_T)s_app_ctx.e_output_chroma_format;
            s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ih264a_aligned_malloc;
            s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ih264a_aligned_free;
            s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = NULL;
            s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ih264d_create_ip_t);
            s_create_op.s_ivd_create_op_t.u4_size = sizeof(ih264d_create_op_t);



            ret = ivd_api_function(NULL, (void *)&s_create_ip,
                                       (void *)&s_create_op);
            if(ret != IV_SUCCESS)
            {
                sprintf(ac_error_str, "Error in Create %8x\n",
                        s_create_op.s_ivd_create_op_t.u4_error_code);
                codec_exit(ac_error_str);
            }
            codec_obj = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
            codec_obj->pv_fxns = fxns;
            codec_obj->u4_size = sizeof(iv_obj_t);
            s_app_ctx.cocodec_obj = codec_obj;

            /*****************************************************************************/
            /*  set stride                                                               */
            /*****************************************************************************/
            {
                ivd_ctl_set_config_ip_t s_ctl_ip;
                ivd_ctl_set_config_op_t s_ctl_op;


                s_ctl_ip.u4_disp_wd = STRIDE;
                if(1 == s_app_ctx.display)
                    s_ctl_ip.u4_disp_wd = s_app_ctx.get_stride();

                s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
                s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
                s_ctl_ip.e_vid_dec_mode = IVD_DECODE_HEADER;
                s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
                s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
                s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
                s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

                ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_ip,
                                           (void *)&s_ctl_op);
                if(ret != IV_SUCCESS)
                {
                    sprintf(ac_error_str,
                            "\nError in setting the stride");
                    codec_exit(ac_error_str);
                }
            }



        }

    }


    /*************************************************************************/
    /* set num of cores                                                      */
    /*************************************************************************/
    {

        ih264d_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
        ih264d_ctl_set_num_cores_op_t s_ctl_set_cores_op;

        s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_set_cores_ip.e_sub_cmd =(IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_SET_NUM_CORES;
        s_ctl_set_cores_ip.u4_num_cores = s_app_ctx.u4_num_cores;
        s_ctl_set_cores_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);
        s_ctl_set_cores_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);

        ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_set_cores_ip,
                                   (void *)&s_ctl_set_cores_op);
        if(ret != IV_SUCCESS)
        {
            sprintf(ac_error_str, "\nError in setting number of cores");
            codec_exit(ac_error_str);
        }

    }

    /*************************************************************************/
    /* set processsor                                                        */
    /*************************************************************************/
    {

        ih264d_ctl_set_processor_ip_t s_ctl_set_num_processor_ip;
        ih264d_ctl_set_processor_op_t s_ctl_set_num_processor_op;

        s_ctl_set_num_processor_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_set_num_processor_ip.e_sub_cmd =(IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_SET_PROCESSOR;
        s_ctl_set_num_processor_ip.u4_arch = s_app_ctx.e_arch;
        s_ctl_set_num_processor_ip.u4_soc = s_app_ctx.e_soc;
        s_ctl_set_num_processor_ip.u4_size = sizeof(ih264d_ctl_set_processor_ip_t);
        s_ctl_set_num_processor_op.u4_size = sizeof(ih264d_ctl_set_processor_op_t);

        ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_set_num_processor_ip,
                                   (void *)&s_ctl_set_num_processor_op);
        if(ret != IV_SUCCESS)
        {
            sprintf(ac_error_str, "\nError in setting Processor type");
            codec_exit(ac_error_str);
        }

    }

    flush_output(codec_obj, &s_app_ctx, ps_out_buf,
                 pu1_bs_buf, &u4_op_frm_ts,
                 ps_op_file, ps_op_chksum_file,
                 u4_ip_frm_ts, u4_bytes_remaining);

    /*****************************************************************************/
    /*   Decode header to get width and height and buffer sizes                  */
    /*****************************************************************************/
    {
        ivd_video_decode_ip_t s_video_decode_ip;
        ivd_video_decode_op_t s_video_decode_op;



        {
            ivd_ctl_set_config_ip_t s_ctl_ip;
            ivd_ctl_set_config_op_t s_ctl_op;


            s_ctl_ip.u4_disp_wd = STRIDE;
            if(1 == s_app_ctx.display)
                s_ctl_ip.u4_disp_wd = s_app_ctx.get_stride();

            s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;
            s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
            s_ctl_ip.e_vid_dec_mode = IVD_DECODE_HEADER;
            s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
            s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
            s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

            ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_ip,
                                       (void *)&s_ctl_op);
            if(ret != IV_SUCCESS)
            {
                sprintf(ac_error_str,
                        "\nError in setting the codec in header decode mode");
                codec_exit(ac_error_str);
            }
        }

        /* Allocate input buffer for header */
        u4_ip_buf_len = 256 * 1024;
        pu1_bs_buf = (UWORD8 *)malloc(u4_ip_buf_len);

        if(pu1_bs_buf == NULL)
        {
            sprintf(ac_error_str,
                    "\nAllocation failure for input buffer of i4_size %d",
                    u4_ip_buf_len);
            codec_exit(ac_error_str);
        }

        do
        {
            WORD32 numbytes;

            if(0 == s_app_ctx.u4_piclen_flag)
            {
                fseek(ps_ip_file, file_pos, SEEK_SET);
                numbytes = u4_ip_buf_len;
            }
            else
            {
                WORD32 entries;
                entries = fscanf(ps_piclen_file, "%d\n", &numbytes);
                if(1 != entries)
                    numbytes = u4_ip_buf_len;
            }

            u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8), numbytes,
                                       ps_ip_file);

            if(0 == u4_bytes_remaining)
            {
                sprintf(ac_error_str, "\nUnable to read from input file");
                codec_exit(ac_error_str);
            }

            s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
            s_video_decode_ip.u4_ts = u4_ip_frm_ts;
            s_video_decode_ip.pv_stream_buffer = pu1_bs_buf;
            s_video_decode_ip.u4_num_Bytes = u4_bytes_remaining;
            s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t);
            s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t);

            /*****************************************************************************/
            /*   API Call: Header Decode                                                  */
            /*****************************************************************************/
            ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_video_decode_ip,
                                       (void *)&s_video_decode_op);

            if(ret != IV_SUCCESS)
            {
                printf("Error in header decode 0x%x\n",  s_video_decode_op.u4_error_code);
                // codec_exit(ac_error_str);
            }

            u4_num_bytes_dec = s_video_decode_op.u4_num_bytes_consumed;
#ifndef PROFILE_ENABLE
            printf("%d\n",s_video_decode_op.u4_num_bytes_consumed);
#endif
            file_pos += u4_num_bytes_dec;
            total_bytes_comsumed += u4_num_bytes_dec;
        }while(ret != IV_SUCCESS);

        /* copy pic_wd and pic_ht to initialize buffers */
        s_app_ctx.u4_pic_wd = s_video_decode_op.u4_pic_wd;
        s_app_ctx.u4_pic_ht = s_video_decode_op.u4_pic_ht;

        free(pu1_bs_buf);

#if IOS_DISPLAY
        s_app_ctx.i4_screen_wd = screen_wd;
        s_app_ctx.i4_screen_ht = screen_ht;
#endif
        {

            ivd_ctl_getbufinfo_ip_t s_ctl_ip;
            ivd_ctl_getbufinfo_op_t s_ctl_op;
            WORD32 outlen = 0;

            s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_GETBUFINFO;
            s_ctl_ip.u4_size = sizeof(ivd_ctl_getbufinfo_ip_t);
            s_ctl_op.u4_size = sizeof(ivd_ctl_getbufinfo_op_t);
            ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_ip,
                                       (void *)&s_ctl_op);
            if(ret != IV_SUCCESS)
            {
                sprintf(ac_error_str, "Error in Get Buf Info %x", s_ctl_op.u4_error_code);
                codec_exit(ac_error_str);
            }

            /* Allocate bitstream buffer */
            u4_ip_buf_len = s_ctl_op.u4_min_in_buf_size[0];
#ifdef ADAPTIVE_TEST
            u4_ip_buf_len = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT * 3 >> 1;
#endif
            pu1_bs_buf = (UWORD8 *)malloc(u4_ip_buf_len);

            if(pu1_bs_buf == NULL)
            {
                sprintf(ac_error_str,
                        "\nAllocation failure for input buffer of i4_size %d",
                        u4_ip_buf_len);
                codec_exit(ac_error_str);
            }

            s_app_ctx.num_disp_buf = s_ctl_op.u4_num_disp_bufs;
            /* Allocate output buffer only if display buffers are not shared */
            /* Or if shared and output is 420P */
            if((0 == s_app_ctx.u4_share_disp_buf) || (IV_YUV_420P == s_app_ctx.e_output_chroma_format))
            {
#ifdef ADAPTIVE_TEST
                switch(s_app_ctx.e_output_chroma_format)
                {
                    case IV_YUV_420P:
                    {
                        s_ctl_op.u4_min_out_buf_size[0] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT;
                        s_ctl_op.u4_min_out_buf_size[1] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT >> 2;
                        s_ctl_op.u4_min_out_buf_size[2] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT >> 2;
                        break;
                    }
                    case IV_YUV_420SP_UV:
                    case IV_YUV_420SP_VU:
                    {
                        s_ctl_op.u4_min_out_buf_size[0] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT;
                        s_ctl_op.u4_min_out_buf_size[1] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT >> 1;
                        s_ctl_op.u4_min_out_buf_size[2] = 0;
                        break;
                    }
                    case IV_YUV_422ILE:
                    {
                        s_ctl_op.u4_min_out_buf_size[0] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT * 2;
                        s_ctl_op.u4_min_out_buf_size[1] = 0;
                        s_ctl_op.u4_min_out_buf_size[2] = 0;
                        break;
                    }
                    case IV_RGBA_8888:
                    {
                        s_ctl_op.u4_min_out_buf_size[0] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT * 4;
                        s_ctl_op.u4_min_out_buf_size[1] = 0;
                        s_ctl_op.u4_min_out_buf_size[2] = 0;
                        break;
                    }
                    case IV_RGB_565:
                    {
                        s_ctl_op.u4_min_out_buf_size[0] = ADAPTIVE_MAX_WD * ADAPTIVE_MAX_HT * 2;
                        s_ctl_op.u4_min_out_buf_size[1] = 0;
                        s_ctl_op.u4_min_out_buf_size[2] = 0;
                        break;
                    }
                    default:
                        break;

                }
#endif
                ps_out_buf->u4_min_out_buf_size[0] =
                                s_ctl_op.u4_min_out_buf_size[0];
                ps_out_buf->u4_min_out_buf_size[1] =
                                s_ctl_op.u4_min_out_buf_size[1];
                ps_out_buf->u4_min_out_buf_size[2] =
                                s_ctl_op.u4_min_out_buf_size[2];

                outlen = s_ctl_op.u4_min_out_buf_size[0];
                if(s_ctl_op.u4_min_num_out_bufs > 1)
                    outlen += s_ctl_op.u4_min_out_buf_size[1];

                if(s_ctl_op.u4_min_num_out_bufs > 2)
                    outlen += s_ctl_op.u4_min_out_buf_size[2];

                ps_out_buf->pu1_bufs[0] = (UWORD8 *)malloc(outlen);
                if(ps_out_buf->pu1_bufs[0] == NULL)
                {
                    sprintf(ac_error_str,
                            "\nAllocation failure for output buffer of i4_size %d",
                            outlen);
                    codec_exit(ac_error_str);
                }

                if(s_ctl_op.u4_min_num_out_bufs > 1)
                    ps_out_buf->pu1_bufs[1] = ps_out_buf->pu1_bufs[0]
                                    + (s_ctl_op.u4_min_out_buf_size[0]);

                if(s_ctl_op.u4_min_num_out_bufs > 2)
                    ps_out_buf->pu1_bufs[2] = ps_out_buf->pu1_bufs[1]
                                    + (s_ctl_op.u4_min_out_buf_size[1]);

                ps_out_buf->u4_num_bufs = s_ctl_op.u4_min_num_out_bufs;
            }

#ifdef APP_EXTRA_BUFS
            s_app_ctx.disp_delay = EXTRA_DISP_BUFFERS;
            s_ctl_op.u4_num_disp_bufs += EXTRA_DISP_BUFFERS;
#endif

            /*****************************************************************************/
            /*   API Call: Allocate display buffers for display buffer shared case       */
            /*****************************************************************************/

            for(i = 0; i < s_ctl_op.u4_num_disp_bufs; i++)
            {

                s_app_ctx.s_disp_buffers[i].u4_min_out_buf_size[0] =
                                s_ctl_op.u4_min_out_buf_size[0];
                s_app_ctx.s_disp_buffers[i].u4_min_out_buf_size[1] =
                                s_ctl_op.u4_min_out_buf_size[1];
                s_app_ctx.s_disp_buffers[i].u4_min_out_buf_size[2] =
                                s_ctl_op.u4_min_out_buf_size[2];

                outlen = s_ctl_op.u4_min_out_buf_size[0];
                if(s_ctl_op.u4_min_num_out_bufs > 1)
                    outlen += s_ctl_op.u4_min_out_buf_size[1];

                if(s_ctl_op.u4_min_num_out_bufs > 2)
                    outlen += s_ctl_op.u4_min_out_buf_size[2];

                s_app_ctx.s_disp_buffers[i].pu1_bufs[0] = (UWORD8 *)malloc(outlen);

                if(s_app_ctx.s_disp_buffers[i].pu1_bufs[0] == NULL)
                {
                    sprintf(ac_error_str,
                            "\nAllocation failure for output buffer of i4_size %d",
                            outlen);
                    codec_exit(ac_error_str);
                }

                if(s_ctl_op.u4_min_num_out_bufs > 1)
                    s_app_ctx.s_disp_buffers[i].pu1_bufs[1] =
                                    s_app_ctx.s_disp_buffers[i].pu1_bufs[0]
                                                    + (s_ctl_op.u4_min_out_buf_size[0]);

                if(s_ctl_op.u4_min_num_out_bufs > 2)
                    s_app_ctx.s_disp_buffers[i].pu1_bufs[2] =
                                    s_app_ctx.s_disp_buffers[i].pu1_bufs[1]
                                                    + (s_ctl_op.u4_min_out_buf_size[1]);

                s_app_ctx.s_disp_buffers[i].u4_num_bufs =
                                s_ctl_op.u4_min_num_out_bufs;
            }
            s_app_ctx.num_disp_buf = s_ctl_op.u4_num_disp_bufs;
        }

        /* Create display thread and wait for the display buffers to be initialized */
        if(1 == s_app_ctx.display)
        {
            if(0 == s_app_ctx.display_thread_created)
            {
                s_app_ctx.display_init_done = 0;
                ithread_create(s_app_ctx.display_thread_handle, NULL,
                                                    (void *) &display_thread, (void *) &s_app_ctx);
                s_app_ctx.display_thread_created = 1;

                while(1)
                {
                    if(s_app_ctx.display_init_done)
                        break;

                    ithread_msleep(1);
                }
            }

            s_app_ctx.u4_strd = s_app_ctx.get_stride();
        }
    }

    /*************************************************************************/
    /* Get actual number of output buffers requried, which is dependent      */
    /* on ps_bitstrm properties such as width, height and level etc              */
    /* This is needed mainly for shared display mode                         */
    /*************************************************************************/
    //if(1 == s_app_ctx.u4_share_disp_buf)
    {
        /*****************************************************************************/
        /*   API Call: Send the allocated display buffers to codec                   */
        /*****************************************************************************/
        {
            ivd_set_display_frame_ip_t s_set_display_frame_ip;
            ivd_set_display_frame_op_t s_set_display_frame_op;

            s_set_display_frame_ip.e_cmd = IVD_CMD_SET_DISPLAY_FRAME;
            s_set_display_frame_ip.u4_size = sizeof(ivd_set_display_frame_ip_t);
            s_set_display_frame_op.u4_size = sizeof(ivd_set_display_frame_op_t);

            s_set_display_frame_ip.num_disp_bufs = s_app_ctx.num_disp_buf;

            memcpy(&(s_set_display_frame_ip.s_disp_buffer),
                   &(s_app_ctx.s_disp_buffers),
                   s_app_ctx.num_disp_buf * sizeof(ivd_out_bufdesc_t));

            ret = ivd_api_function((iv_obj_t *)codec_obj,
                                       (void *)&s_set_display_frame_ip,
                                       (void *)&s_set_display_frame_op);

            if(IV_SUCCESS != ret)
            {
                sprintf(ac_error_str, "Error in Set display frame");
                codec_exit(ac_error_str);
            }

        }

    }

    /*************************************************************************/
    /* Get frame dimensions for display buffers such as x_offset,y_offset    */
    /* etc. This information might be needed to set display buffer           */
    /* offsets in case of shared display buffer mode                         */
    /*************************************************************************/
    {

        ih264d_ctl_get_frame_dimensions_ip_t s_ctl_get_frame_dimensions_ip;
        ih264d_ctl_get_frame_dimensions_op_t s_ctl_get_frame_dimensions_op;

        s_ctl_get_frame_dimensions_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_get_frame_dimensions_ip.e_sub_cmd =
                        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_BUFFER_DIMENSIONS;
        s_ctl_get_frame_dimensions_ip.u4_size =
                        sizeof(ih264d_ctl_get_frame_dimensions_ip_t);
        s_ctl_get_frame_dimensions_op.u4_size =
                        sizeof(ih264d_ctl_get_frame_dimensions_op_t);

        ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_get_frame_dimensions_ip,
                             (void *)&s_ctl_get_frame_dimensions_op);
        if(IV_SUCCESS != ret)
        {
            sprintf(ac_error_str, "Error in Get buffer Dimensions");
            codec_exit(ac_error_str);
        }

/*
        printf("Frame offsets due to padding\n");
        printf("s_ctl_get_frame_dimensions_op.x_offset[0] %d s_ctl_get_frame_dimensions_op.y_offset[0] %d\n",
               s_ctl_get_frame_dimensions_op.u4_x_offset[0],
               s_ctl_get_frame_dimensions_op.u4_y_offset[0]);
*/
    }

    /*************************************************************************/
    /* Get VUI parameters                                                    */
    /*************************************************************************/
    {

        ih264d_ctl_get_vui_params_ip_t s_ctl_get_vui_params_ip;
        ih264d_ctl_get_vui_params_op_t s_ctl_get_vui_params_op;

        s_ctl_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_get_vui_params_ip.e_sub_cmd =
                        (IVD_CONTROL_API_COMMAND_TYPE_T)IH264D_CMD_CTL_GET_VUI_PARAMS;
        s_ctl_get_vui_params_ip.u4_size =
                        sizeof(ih264d_ctl_get_vui_params_ip_t);
        s_ctl_get_vui_params_op.u4_size =
                        sizeof(ih264d_ctl_get_vui_params_op_t);

        ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_get_vui_params_ip,
                             (void *)&s_ctl_get_vui_params_op);
        if(IV_SUCCESS != ret)
        {
            sprintf(ac_error_str, "Error in Get VUI params");
            //codec_exit(ac_error_str);
        }
    }

    /*************************************************************************/
    /* Set the decoder in frame decode mode. It was set in header decode     */
    /* mode earlier                                                          */
    /*************************************************************************/
    {

        ivd_ctl_set_config_ip_t s_ctl_ip;
        ivd_ctl_set_config_op_t s_ctl_op;

        s_ctl_ip.u4_disp_wd = STRIDE;
        if(1 == s_app_ctx.display)
            s_ctl_ip.u4_disp_wd = s_app_ctx.get_stride();
        s_ctl_ip.e_frm_skip_mode = IVD_SKIP_NONE;

        s_ctl_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
        s_ctl_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
        s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
        s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
        s_ctl_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);

        s_ctl_op.u4_size = sizeof(ivd_ctl_set_config_op_t);

        ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip, (void *)&s_ctl_op);

        if(IV_SUCCESS != ret)
        {
            sprintf(ac_error_str, "Error in Set Parameters");
            //codec_exit(ac_error_str);
        }

    }
    /*************************************************************************/
    /* If required disable deblocking and sao at given level                 */
    /*************************************************************************/

    set_degrade(codec_obj, s_app_ctx.i4_degrade_type, s_app_ctx.i4_degrade_pics);
#ifdef WINDOWS_TIMER
        QueryPerformanceFrequency ( &frequency);
#endif
#ifndef PRINT_PICSIZE
    get_version(codec_obj);
#endif


    max_op_frm_ts = s_app_ctx.u4_max_frm_ts + s_app_ctx.disp_delay;

    if(max_op_frm_ts <  s_app_ctx.disp_delay)
        max_op_frm_ts = 0xffffffff;/* clip as overflow has occured*/

    max_op_frm_ts = (s_app_ctx.u4_max_frm_ts > 0)? (max_op_frm_ts): 0xffffffff;

    u4_num_disp_bufs_with_dec = 0;

    while(u4_op_frm_ts < max_op_frm_ts)
    {

#ifdef TEST_FLUSH
        if(u4_ip_frm_ts == FLUSH_FRM_CNT)
        {
            ivd_ctl_flush_ip_t s_ctl_ip;
            ivd_ctl_flush_op_t s_ctl_op;

            s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
            s_ctl_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
            s_ctl_op.u4_size = sizeof(ivd_ctl_flush_op_t);
            ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                       (void *)&s_ctl_op);

            if(ret != IV_SUCCESS)
            {
                printf("Error in Setting the decoder in flush mode\n");
            }
//            file_pos = 0;

//          fseek(ps_ip_file, file_pos, SEEK_SET);

        }
#endif
        if(u4_num_disp_bufs_with_dec < s_app_ctx.num_disp_buf)
        {
            release_disp_frame(codec_obj, u4_num_disp_bufs_with_dec);
            u4_num_disp_bufs_with_dec ++;
        }


        /*************************************************************************/
        /* set num of cores                                                      */
        /*************************************************************************/
#ifdef DYNAMIC_NUMCORES
        {

            ih264d_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
            ih264d_ctl_set_num_cores_op_t s_ctl_set_cores_op;

            s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
            s_ctl_set_cores_ip.e_sub_cmd = IH264D_CMD_CTL_SET_NUM_CORES;
            s_ctl_set_cores_ip.u4_num_cores =  1 + 3 * (u4_ip_frm_ts % 2);
            s_ctl_set_cores_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);
            s_ctl_set_cores_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);

            ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_set_cores_ip,
                                       (void *)&s_ctl_set_cores_op);
            if(ret != IV_SUCCESS)
            {
                sprintf(ac_error_str, "\nError in setting number of cores");
                codec_exit(ac_error_str);
            }

        }
#endif
        /***********************************************************************/
        /*   Seek the file to start of current frame, this is equavelent of    */
        /*   having a parcer which tells the start of current frame            */
        /***********************************************************************/
        {
            WORD32 numbytes;

            if(0 == s_app_ctx.u4_piclen_flag)
            {
                fseek(ps_ip_file, file_pos, SEEK_SET);
                numbytes = u4_ip_buf_len;
            }
            else
            {
                WORD32 entries;
                entries = fscanf(ps_piclen_file, "%d\n", &numbytes);
                if(1 != entries)
                    numbytes = u4_ip_buf_len;
            }

            u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8),
                                       numbytes, ps_ip_file);

            if(u4_bytes_remaining == 0)
            {
                if(1 == s_app_ctx.loopback)
                {
                    file_pos = 0;
                    if(0 == s_app_ctx.u4_piclen_flag)
                    {
                        fseek(ps_ip_file, file_pos, SEEK_SET);
                        numbytes = u4_ip_buf_len;
                    }
                    else
                    {
                        WORD32 entries;
                        entries = fscanf(ps_piclen_file, "%d\n", &numbytes);
                        if(1 != entries)
                            numbytes = u4_ip_buf_len;
                    }


                    u4_bytes_remaining = fread(pu1_bs_buf, sizeof(UWORD8),
                                               numbytes, ps_ip_file);
                }
                else
                    break;
            }
        }

        /*********************************************************************/
        /* Following calls can be enabled at diffent times                   */
        /*********************************************************************/
#if ENABLE_DEGRADE
        if(u4_op_frm_ts >= 10000)
            disable_deblocking(codec_obj, 4);

        if(u4_op_frm_ts == 30000)
            enable_deblocking(codec_obj);

        if(u4_op_frm_ts == 10000)
            enable_skippb_frames(codec_obj);

        if(u4_op_frm_ts == 60000)
            disable_skippb_frames(codec_obj);

        if(u4_op_frm_ts == 30000)
            enable_skipb_frames(codec_obj);

        if(u4_op_frm_ts == 60000)
            disable_skipb_frames(codec_obj);
#endif


        {
            ivd_video_decode_ip_t s_video_decode_ip;
            ivd_video_decode_op_t s_video_decode_op;
#ifdef PROFILE_ENABLE
            UWORD32 s_elapsed_time;
            TIMER s_start_timer;
            TIMER s_end_timer;
#endif


            s_video_decode_ip.e_cmd = IVD_CMD_VIDEO_DECODE;
            s_video_decode_ip.u4_ts = u4_ip_frm_ts;
            s_video_decode_ip.pv_stream_buffer = pu1_bs_buf;
            s_video_decode_ip.u4_num_Bytes = u4_bytes_remaining;
            s_video_decode_ip.u4_size = sizeof(ivd_video_decode_ip_t);
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[0] =
                            ps_out_buf->u4_min_out_buf_size[0];
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[1] =
                            ps_out_buf->u4_min_out_buf_size[1];
            s_video_decode_ip.s_out_buffer.u4_min_out_buf_size[2] =
                            ps_out_buf->u4_min_out_buf_size[2];

            s_video_decode_ip.s_out_buffer.pu1_bufs[0] =
                            ps_out_buf->pu1_bufs[0];
            s_video_decode_ip.s_out_buffer.pu1_bufs[1] =
                            ps_out_buf->pu1_bufs[1];
            s_video_decode_ip.s_out_buffer.pu1_bufs[2] =
                            ps_out_buf->pu1_bufs[2];
            s_video_decode_ip.s_out_buffer.u4_num_bufs =
                            ps_out_buf->u4_num_bufs;
            s_video_decode_op.u4_size = sizeof(ivd_video_decode_op_t);

            /* Get display buffer pointers */
            if(1 == s_app_ctx.display)
            {
                WORD32 wr_idx;

                wr_idx = dispq_producer_dequeue(&s_app_ctx);

                if(s_app_ctx.quit)
                    break;

                s_app_ctx.set_disp_buffers(s_app_ctx.pv_disp_ctx, wr_idx,
                                     &s_video_decode_ip.s_out_buffer.pu1_bufs[0],
                                     &s_video_decode_ip.s_out_buffer.pu1_bufs[1],
                                     &s_video_decode_ip.s_out_buffer.pu1_bufs[2]);
            }

            /*****************************************************************************/
            /*   API Call: Video Decode                                                  */
            /*****************************************************************************/

            GETTIME(&s_start_timer);

            ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_video_decode_ip,
                                       (void *)&s_video_decode_op);


            GETTIME(&s_end_timer);
            ELAPSEDTIME(s_start_timer,s_end_timer,s_elapsed_time,frequency);
#ifdef PROFILE_ENABLE
            {
                    UWORD32 peak_avg, id;
                    u4_tot_cycles += s_elapsed_time;
                    peak_window[peak_window_idx++] = s_elapsed_time;
                    if(peak_window_idx == PEAK_WINDOW_SIZE)
                    peak_window_idx = 0;
                    peak_avg = 0;
                    for(id = 0; id < PEAK_WINDOW_SIZE; id++)
                    {
                            peak_avg += peak_window[id];
                    }
                    peak_avg /= PEAK_WINDOW_SIZE;
                    if(peak_avg > peak_avg_max)
                    peak_avg_max = peak_avg;
                    frm_cnt++;

                    printf("FrameNum: %4d TimeTaken(microsec): %6d AvgTime: %6d PeakAvgTimeMax: %6d Output: %2d NumBytes: %6d \n",
                                    frm_cnt, s_elapsed_time, u4_tot_cycles / frm_cnt, peak_avg_max, s_video_decode_op.u4_output_present, s_video_decode_op.u4_num_bytes_consumed);

            }
#ifdef INTEL_CE5300
        time_consumed += s_elapsed_time;
        bytes_consumed += s_video_decode_op.u4_num_bytes_consumed;
        if (!(frm_cnt % (s_app_ctx.fps)))
        {
            time_consumed = time_consumed/s_app_ctx.fps;
            printf("Average decode time(micro sec) for the last second = %6d\n",time_consumed);
            printf("Average bitrate(kb) for the last second = %6d\n",(bytes_consumed * 8) / 1024);
            time_consumed = 0;
            bytes_consumed = 0;

        }
#endif
#else
        printf("%d\n",s_video_decode_op.u4_num_bytes_consumed);
#endif

            if(ret != IV_SUCCESS)
            {
                printf("Error in video Frame decode : ret %x Error %x\n", ret,
                       s_video_decode_op.u4_error_code);
            }

            if((IV_SUCCESS != ret) &&
                            ((s_video_decode_op.u4_error_code & 0xFF) == IVD_RES_CHANGED))
            {
                ivd_ctl_reset_ip_t s_ctl_ip;
                ivd_ctl_reset_op_t s_ctl_op;

                flush_output(codec_obj, &s_app_ctx, ps_out_buf,
                             pu1_bs_buf, &u4_op_frm_ts,
                             ps_op_file, ps_op_chksum_file,
                             u4_ip_frm_ts, u4_bytes_remaining);

                s_ctl_ip.e_cmd = IVD_CMD_VIDEO_CTL;
                s_ctl_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
                s_ctl_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
                s_ctl_op.u4_size = sizeof(ivd_ctl_reset_op_t);

                ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_ctl_ip,
                                                   (void *)&s_ctl_op);
                if(IV_SUCCESS != ret)
                {
                    sprintf(ac_error_str, "Error in Reset");
                    codec_exit(ac_error_str);
                }

                /*when reset all buffers are released by lib*/
                u4_num_disp_bufs_with_dec = 0;
                /*************************************************************************/
                /* set num of cores                                                      */
                /*************************************************************************/
                {

                    ih264d_ctl_set_num_cores_ip_t s_ctl_set_cores_ip;
                    ih264d_ctl_set_num_cores_op_t s_ctl_set_cores_op;

                    s_ctl_set_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
                    s_ctl_set_cores_ip.e_sub_cmd =(IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_SET_NUM_CORES;
                    s_ctl_set_cores_ip.u4_num_cores = s_app_ctx.u4_num_cores;
                    s_ctl_set_cores_ip.u4_size = sizeof(ih264d_ctl_set_num_cores_ip_t);
                    s_ctl_set_cores_op.u4_size = sizeof(ih264d_ctl_set_num_cores_op_t);

                    ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_set_cores_ip,
                                               (void *)&s_ctl_set_cores_op);
                    if(ret != IV_SUCCESS)
                    {
                        sprintf(ac_error_str, "\nError in setting number of cores");
                        codec_exit(ac_error_str);
                    }

                }
                /*************************************************************************/
                /* set processsor                                                        */
                /*************************************************************************/

                {

                    ih264d_ctl_set_processor_ip_t s_ctl_set_num_processor_ip;
                    ih264d_ctl_set_processor_op_t s_ctl_set_num_processor_op;

                    s_ctl_set_num_processor_ip.e_cmd = IVD_CMD_VIDEO_CTL;
                    s_ctl_set_num_processor_ip.e_sub_cmd =(IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_SET_PROCESSOR;
                    s_ctl_set_num_processor_ip.u4_arch = s_app_ctx.e_arch;
                    s_ctl_set_num_processor_ip.u4_soc = s_app_ctx.e_soc;
                    s_ctl_set_num_processor_ip.u4_size = sizeof(ih264d_ctl_set_processor_ip_t);
                    s_ctl_set_num_processor_op.u4_size = sizeof(ih264d_ctl_set_processor_op_t);

                    ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_ctl_set_num_processor_ip,
                                               (void *)&s_ctl_set_num_processor_op);
                    if(ret != IV_SUCCESS)
                    {
                        sprintf(ac_error_str, "\nError in setting Processor type");
                        codec_exit(ac_error_str);
                    }

                }
            }


            if((1 == s_app_ctx.display) &&
                            (1 == s_video_decode_op.u4_output_present))
            {
                dispq_producer_queue(&s_app_ctx);
            }

            if(IV_B_FRAME == s_video_decode_op.e_pic_type)
                s_app_ctx.b_pic_present |= 1;

            u4_num_bytes_dec = s_video_decode_op.u4_num_bytes_consumed;

            file_pos += u4_num_bytes_dec;
            total_bytes_comsumed += u4_num_bytes_dec;
            u4_ip_frm_ts++;


            if(1 == s_video_decode_op.u4_output_present)
            {

                CHAR cur_fname[1000];
                CHAR *extn = NULL;
                /* The objective is to dump the decoded frames into separate files instead of
                 * dumping all the frames in one common file. Also, the number of dumped frames
                 * at any given instance of time cannot exceed 'frame_memory'
                 */
                if(s_app_ctx.u4_file_save_flag)
                {
                    /* Locate the position of extension yuv */
                    extn = strstr(s_app_ctx.ac_op_fname,"%d");
                    if (extn != NULL)
                    {
                        output_write_stall(s_app_ctx.ac_op_fname,u4_op_frm_ts);
                        /* Generate output file names */
                        sprintf(cur_fname,s_app_ctx.ac_op_fname,u4_op_frm_ts);
                        /* Open Output file */
                        ps_op_file = fopen(cur_fname,"wb");
                        if (NULL == ps_op_file)
                        {
                            sprintf(ac_error_str, "Could not open output file %s",
                                    cur_fname);

                            codec_exit(ac_error_str);
                        }
                    }
                }

                width = s_video_decode_op.s_disp_frm_buf.u4_y_wd;
                height = s_video_decode_op.s_disp_frm_buf.u4_y_ht;
                dump_output(&s_app_ctx, &(s_video_decode_op.s_disp_frm_buf),
                            s_video_decode_op.u4_disp_buf_id, ps_op_file,
                            ps_op_chksum_file,
                            u4_op_frm_ts, s_app_ctx.u4_file_save_flag,
                            s_app_ctx.u4_chksum_save_flag);

                u4_op_frm_ts++;
                if (extn != NULL)
                    fclose(ps_op_file);

            }
            else
            {
                if((s_video_decode_op.u4_error_code >> IVD_FATALERROR) & 1)
                {
                    printf("Fatal error\n");
                    break;
                }
            }

        }
    }

    /***********************************************************************/
    /*      To get the last decoded frames, call process with NULL input    */
    /***********************************************************************/
    flush_output(codec_obj, &s_app_ctx, ps_out_buf,
                 pu1_bs_buf, &u4_op_frm_ts,
                 ps_op_file, ps_op_chksum_file,
                 u4_ip_frm_ts, u4_bytes_remaining);

    /* set disp_end u4_flag */
    s_app_ctx.quit = 1;


#ifdef PROFILE_ENABLE
    printf("Summary\n");
    printf("Input filename                  : %s\n", s_app_ctx.ac_ip_fname);
    printf("Output Width                    : %-4d\n", width);
    printf("Output Height                   : %-4d\n", height);

    if(frm_cnt)
    {
        double avg = u4_tot_cycles / frm_cnt;
        double bytes_avg = total_bytes_comsumed / frm_cnt;
        double bitrate = (bytes_avg * 8 * s_app_ctx.fps)/1000000;
        printf("Bitrate @ %2d fps(mbps)          : %-6.2f\n", s_app_ctx.fps, bitrate);
        printf("Average decode time(micro sec)  : %-6d\n", (WORD32)avg);
        printf("Avg Peak decode time(%2d frames) : %-6d\n", PEAK_WINDOW_SIZE, (WORD32)peak_avg_max);
        avg = (u4_tot_cycles + u4_tot_fmt_cycles)* 1.0 / frm_cnt;

        if(0 == s_app_ctx.u4_share_disp_buf)
            printf("FPS achieved (with format conv) : %-3.2f\n", 1000000/avg);
        else
            printf("FPS achieved                    : %-3.2f\n", 1000000/avg);
    }
#endif
    /***********************************************************************/
    /*   Clear the decoder, close all the files, free all the memory       */
    /***********************************************************************/
    if(1 == s_app_ctx.display)
    {
        s_app_ctx.display_deinit_flag = 1;
        /* wait for display to finish */
        if(s_app_ctx.display_thread_created)
        {
            ithread_join(s_app_ctx.display_thread_handle, NULL);
        }
        free(s_app_ctx.display_thread_handle);
    }

    {
        ivd_delete_ip_t s_delete_dec_ip;
        ivd_delete_op_t s_delete_dec_op;

        s_delete_dec_ip.e_cmd = IVD_CMD_DELETE;
        s_delete_dec_ip.u4_size = sizeof(ivd_delete_ip_t);
        s_delete_dec_op.u4_size = sizeof(ivd_delete_op_t);

        ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_delete_dec_ip,
                                   (void *)&s_delete_dec_op);

        if(IV_SUCCESS != ret)
        {
            sprintf(ac_error_str, "Error in Codec delete");
            codec_exit(ac_error_str);
        }
    }
    /***********************************************************************/
    /*              Close all the files and free all the memory            */
    /***********************************************************************/
    {
        fclose(ps_ip_file);

        if((1 == s_app_ctx.u4_file_save_flag) && (strstr(s_app_ctx.ac_op_fname,"%d") == NULL))
        {
            fclose(ps_op_file);
        }
        if(1 == s_app_ctx.u4_chksum_save_flag)
        {
            fclose(ps_op_chksum_file);
        }

    }

    if(0 == s_app_ctx.u4_share_disp_buf)
    {
        free(ps_out_buf->pu1_bufs[0]);
    }

    for(i = 0; i < s_app_ctx.num_disp_buf; i++)
    {
        free(s_app_ctx.s_disp_buffers[i].pu1_bufs[0]);
    }

    free(ps_out_buf);
    free(pu1_bs_buf);

    if(s_app_ctx.display_thread_handle)
        free(s_app_ctx.display_thread_handle);

    return (0);
}