libavc/test/decoder/main.c
Marco Nelissen 8ef4c3f614 Multithreading changes and better error resilience
Fixed the following bugs
Issue 21145276
Issue 21144884
Issue 21181133
Issue 21181134

Decoder now returns error if the level in stream is higher than level at init

Change-Id: I8892c62bd98f7854d046510330c05a1e9ca826b2
2015-06-03 07:27:36 -07:00

3231 lines
130 KiB
C

/******************************************************************************
*
* 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 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 max_wd;
UWORD32 max_ht;
UWORD32 max_level;
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,
MAX_WD,
MAX_HT,
MAX_LEVEL,
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"},
{ "--", "--max_wd", MAX_WD,
"Maximum width (Default: 2560) \n" },
{ "--", "--max_ht", MAX_HT,
"Maximum height (Default: 1600)\n" },
{ "--", "--max_level", MAX_LEVEL,
"Maximum Decoder Level (Default: 50)\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 MAX_FRAME_WIDTH 2560
#define MAX_FRAME_HEIGHT 1600
#define MAX_LEVEL_SUPPORTED 50
#define MAX_REF_FRAMES 16
#define MAX_REORDER_FRAMES 16
#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(WORD32 alignment, WORD32 i4_size)
{
return (void *)_aligned_malloc(i4_size, alignment);
}
void ih264a_aligned_free(void *pv_buf)
{
_aligned_free(pv_buf);
return;
}
#endif
#if IOS
void * ih264a_aligned_malloc(WORD32 alignment, WORD32 i4_size)
{
return malloc(i4_size);
}
void ih264a_aligned_free(void *pv_buf)
{
free(pv_buf);
return;
}
#endif
#if (!defined(IOS)) && (!defined(_WIN32))
void * ih264a_aligned_malloc(WORD32 alignment, WORD32 i4_size)
{
return memalign(alignment, i4_size);
}
void ih264a_aligned_free(void *pv_buf)
{
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 MAX_WD:
sscanf(value, "%d", &ps_app_ctx->max_wd);
break;
case MAX_HT:
sscanf(value, "%d", &ps_app_ctx->max_ht);
break;
case MAX_LEVEL:
sscanf(value, "%d", &ps_app_ctx->max_level);
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->max_wd,
ps_app_ctx->max_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);
/* destroy the display thread */
ithread_exit(ps_app_ctx->display_thread_handle);
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;
ivd_out_bufdesc_t *ps_out_buf;
UWORD32 u4_num_bytes_dec = 0;
UWORD32 file_pos = 0;
IV_API_CALL_STATUS_T e_dec_status;
UWORD32 u4_ip_frm_ts = 0, u4_op_frm_ts = 0;
WORD32 u4_bytes_remaining = 0;
void *pv_mem_rec_location;
UWORD32 u4_num_mem_recs;
UWORD32 i;
UWORD32 u4_ip_buf_len;
UWORD32 frm_cnt = 0;
WORD32 total_bytes_comsumed;
UWORD32 max_op_frm_ts;
#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.max_wd = 0;
s_app_ctx.max_ht = 0;
s_app_ctx.max_level = 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));
{
iv_num_mem_rec_ip_t s_no_of_mem_rec_query_ip;
iv_num_mem_rec_op_t s_no_of_mem_rec_query_op;
s_no_of_mem_rec_query_ip.u4_size = sizeof(s_no_of_mem_rec_query_ip);
s_no_of_mem_rec_query_op.u4_size = sizeof(s_no_of_mem_rec_query_op);
s_no_of_mem_rec_query_ip.e_cmd = IV_CMD_GET_NUM_MEM_REC;
/*****************************************************************************/
/* API Call: Get Number of Mem Records */
/*****************************************************************************/
e_dec_status = ivd_api_function(
NULL, (void*)&s_no_of_mem_rec_query_ip,
(void*)&s_no_of_mem_rec_query_op);
if(IV_SUCCESS != e_dec_status)
{
sprintf(ac_error_str, "Error in get mem records");
codec_exit(ac_error_str);
}
u4_num_mem_recs = s_no_of_mem_rec_query_op.u4_num_mem_rec;
}
pv_mem_rec_location = malloc(u4_num_mem_recs * sizeof(iv_mem_rec_t));
if(pv_mem_rec_location == NULL)
{
sprintf(ac_error_str, "Allocation failure for mem_rec_location");
codec_exit(ac_error_str);
}
{
ih264d_fill_mem_rec_ip_t s_fill_mem_rec_ip;
ih264d_fill_mem_rec_op_t s_fill_mem_rec_op;
iv_mem_rec_t *ps_mem_rec;
UWORD32 total_size;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.e_cmd =
IV_CMD_FILL_NUM_MEM_REC;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.pv_mem_rec_location =
(iv_mem_rec_t *)pv_mem_rec_location;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_wd =
(s_app_ctx.max_wd == 0) ? MAX_FRAME_WIDTH : s_app_ctx.max_wd;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_max_frm_ht =
(s_app_ctx.max_ht == 0) ? MAX_FRAME_HEIGHT : s_app_ctx.max_ht;
s_fill_mem_rec_ip.i4_level = (s_app_ctx.max_level == 0) ? MAX_LEVEL_SUPPORTED : s_app_ctx.max_level;
s_fill_mem_rec_ip.u4_num_ref_frames = MAX_REF_FRAMES;
s_fill_mem_rec_ip.u4_num_reorder_frames = MAX_REORDER_FRAMES;
s_fill_mem_rec_ip.u4_share_disp_buf = s_app_ctx.u4_share_disp_buf;
s_fill_mem_rec_ip.e_output_format =
(IV_COLOR_FORMAT_T)s_app_ctx.e_output_chroma_format;
s_fill_mem_rec_ip.u4_num_extra_disp_buf = EXTRA_DISP_BUFFERS;
s_fill_mem_rec_ip.s_ivd_fill_mem_rec_ip_t.u4_size =
sizeof(ih264d_fill_mem_rec_ip_t);
s_fill_mem_rec_op.s_ivd_fill_mem_rec_op_t.u4_size =
sizeof(ih264d_fill_mem_rec_op_t);
ps_mem_rec = (iv_mem_rec_t *)pv_mem_rec_location;
for(i = 0; i < u4_num_mem_recs; i++)
ps_mem_rec[i].u4_size = sizeof(iv_mem_rec_t);
/*****************************************************************************/
/* API Call: Fill Mem Records */
/*****************************************************************************/
e_dec_status = ivd_api_function(NULL,
(void *)&s_fill_mem_rec_ip,
(void *)&s_fill_mem_rec_op);
u4_num_mem_recs =
s_fill_mem_rec_op.s_ivd_fill_mem_rec_op_t.u4_num_mem_rec_filled;
if(IV_SUCCESS != e_dec_status)
{
sprintf(ac_error_str, "Error in fill mem records: %x",s_fill_mem_rec_op.s_ivd_fill_mem_rec_op_t.u4_error_code);
codec_exit(ac_error_str);
}
ps_mem_rec = (iv_mem_rec_t *)pv_mem_rec_location;
total_size = 0;
for(i = 0; i < u4_num_mem_recs; i++)
{
ps_mem_rec->pv_base = ih264a_aligned_malloc(ps_mem_rec->u4_mem_alignment,
ps_mem_rec->u4_mem_size);
if(ps_mem_rec->pv_base == NULL)
{
sprintf(ac_error_str,
"\nAllocation failure for mem record id %d i4_size %d\n",
i, ps_mem_rec->u4_mem_size);
codec_exit(ac_error_str);
}
total_size += ps_mem_rec->u4_mem_size;
ps_mem_rec++;
}
printf("\nTotal memory for codec %d\n", total_size);
}
/*****************************************************************************/
/* API Call: Initialize the Decoder */
/*****************************************************************************/
{
ih264d_init_ip_t s_init_ip;
ih264d_init_op_t s_init_op;
void *fxns = &ivd_api_function;
iv_mem_rec_t *mem_tab;
mem_tab = (iv_mem_rec_t*)pv_mem_rec_location;
s_init_ip.s_ivd_init_ip_t.e_cmd = (IVD_API_COMMAND_TYPE_T)IV_CMD_INIT;
s_init_ip.s_ivd_init_ip_t.pv_mem_rec_location = mem_tab;
s_init_ip.s_ivd_init_ip_t.u4_frm_max_wd = (s_app_ctx.max_wd == 0) ? MAX_FRAME_WIDTH : s_app_ctx.max_wd;
s_init_ip.s_ivd_init_ip_t.u4_frm_max_ht = (s_app_ctx.max_ht == 0) ? MAX_FRAME_HEIGHT : s_app_ctx.max_ht;
s_init_ip.i4_level = (s_app_ctx.max_level == 0) ? MAX_LEVEL_SUPPORTED : s_app_ctx.max_level;
s_init_ip.u4_num_ref_frames = MAX_REF_FRAMES;
s_init_ip.u4_num_reorder_frames = MAX_REORDER_FRAMES;
s_init_ip.u4_share_disp_buf = s_app_ctx.u4_share_disp_buf;
s_init_ip.u4_num_extra_disp_buf = EXTRA_DISP_BUFFERS;
s_init_ip.s_ivd_init_ip_t.u4_num_mem_rec = u4_num_mem_recs;
s_init_ip.s_ivd_init_ip_t.e_output_format =
(IV_COLOR_FORMAT_T)s_app_ctx.e_output_chroma_format;
s_init_ip.s_ivd_init_ip_t.u4_size = sizeof(ih264d_init_ip_t);
s_init_op.s_ivd_init_op_t.u4_size = sizeof(ih264d_init_op_t);
codec_obj = (iv_obj_t*)mem_tab[0].pv_base;
codec_obj->pv_fxns = fxns;
codec_obj->u4_size = sizeof(iv_obj_t);
s_app_ctx.cocodec_obj = codec_obj;
ret = ivd_api_function((iv_obj_t*)codec_obj, (void *)&s_init_ip,
(void *)&s_init_op);
if(ret != IV_SUCCESS)
{
sprintf(ac_error_str, "Error in Init %8x\n",
s_init_op.s_ivd_init_op_t.u4_error_code);
codec_exit(ac_error_str);
}
/*****************************************************************************/
/* 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_DECODE_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);
}
}
/*****************************************************************************/
/* Input and output buffer allocation */
/*****************************************************************************/
{
ivd_ctl_getbufinfo_ip_t s_ctl_ip;
ivd_ctl_getbufinfo_op_t s_ctl_op;
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 input buffer */
u4_ip_buf_len = s_ctl_op.u4_min_in_buf_size[0];
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))
{
UWORD32 outlen;
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;
}
}
}
}
/*************************************************************************/
/* 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);
}
}
/*****************************************************************************/
/* Decode header to get width and height and buffer sizes */
/*****************************************************************************/
{
ivd_ctl_set_config_ip_t s_ctl_ip;
ivd_ctl_set_config_op_t s_ctl_op;
ivd_video_decode_ip_t s_video_decode_ip;
ivd_video_decode_op_t s_video_decode_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);
}
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;
#if IOS_DISPLAY
s_app_ctx.i4_screen_wd = screen_wd;
s_app_ctx.i4_screen_ht = screen_ht;
#endif
/* 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)
{
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);
}
#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;
/*****************************************************************************/
/* 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_ctl_op.u4_num_disp_bufs * 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]);
*/
}
/*************************************************************************/
/* 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 > 0)? (s_app_ctx.u4_max_frm_ts + s_app_ctx.disp_delay): 0xffffffff;
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_ip_frm_ts < s_app_ctx.num_disp_buf)
{
release_disp_frame(codec_obj, u4_ip_frm_ts);
}
/*************************************************************************/
/* 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);
}
/*************************************************************************/
/* 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);
}
{
iv_retrieve_mem_rec_ip_t s_retrieve_dec_ip;
iv_retrieve_mem_rec_op_t s_retrieve_dec_op;
s_retrieve_dec_ip.pv_mem_rec_location = (iv_mem_rec_t *)pv_mem_rec_location;
s_retrieve_dec_ip.e_cmd = IV_CMD_RETRIEVE_MEMREC;
s_retrieve_dec_ip.u4_size = sizeof(iv_retrieve_mem_rec_ip_t);
s_retrieve_dec_op.u4_size = sizeof(iv_retrieve_mem_rec_op_t);
ret = ivd_api_function((iv_obj_t *)codec_obj, (void *)&s_retrieve_dec_ip,
(void *)&s_retrieve_dec_op);
if(IV_SUCCESS != ret)
{
sprintf(ac_error_str, "Error in Retrieve Memrec");
codec_exit(ac_error_str);
}
{
iv_mem_rec_t *ps_mem_rec;
UWORD16 u2_i;
u4_num_mem_recs = s_retrieve_dec_op.u4_num_mem_rec_filled;
ps_mem_rec = s_retrieve_dec_ip.pv_mem_rec_location;
for(u2_i = 0; u2_i < u4_num_mem_recs; u2_i++)
{
ih264a_aligned_free(ps_mem_rec->pv_base);
ps_mem_rec++;
}
free(s_retrieve_dec_ip.pv_mem_rec_location);
}
}
/***********************************************************************/
/* 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);
return (0);
}