/*-------------------------------------------------------------------------- Copyright (c) 2010 - 2014, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of The Linux Foundation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------*/ /* An Open max test application .... */ #define LOG_TAG "OMX-VDEC-TEST" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "OMX_QCOMExtns.h" #include #include #ifdef _ANDROID_ #include extern "C" { #include } #define DEBUG_PRINT #define DEBUG_PRINT_ERROR ALOGE //#define __DEBUG_DIVX__ // Define this macro to print (through logcat) // the kind of frames packed per buffer and // timestamps adjustments for divx. //#define TEST_TS_FROM_SEI // Define this macro to calculate the timestamps // from the SEI and VUI data for H264 #else #include #define strlcpy g_strlcpy #define ALOGE(fmt, args...) fprintf(stderr, fmt, ##args) #define DEBUG_PRINT printf #define DEBUG_PRINT_ERROR printf #endif /* _ANDROID_ */ #include "OMX_Core.h" #include "OMX_Component.h" #include "OMX_QCOMExtns.h" extern "C" { #include "queue.h" } #include #include #include /************************************************************************/ /* #DEFINES */ /************************************************************************/ #define DELAY 66 #define false 0 #define true 1 #define H264_START_CODE 0x00000001 #define VOP_START_CODE 0x000001B6 #define SHORT_HEADER_START_CODE 0x00008000 #define MPEG2_FRAME_START_CODE 0x00000100 #define MPEG2_SEQ_START_CODE 0x000001B3 #define VC1_START_CODE 0x00000100 #define VC1_FRAME_START_CODE 0x0000010D #define VC1_FRAME_FIELD_CODE 0x0000010C #define VC1_SEQUENCE_START_CODE 0x0000010F #define VC1_ENTRY_POINT_START_CODE 0x0000010E #define NUMBER_OF_ARBITRARYBYTES_READ (4 * 1024) #define VC1_SEQ_LAYER_SIZE_WITHOUT_STRUCTC 32 #define VC1_SEQ_LAYER_SIZE_V1_WITHOUT_STRUCTC 16 static int previous_vc1_au = 0; #define CONFIG_VERSION_SIZE(param) \ param.nVersion.nVersion = CURRENT_OMX_SPEC_VERSION;\ param.nSize = sizeof(param); #define FAILED(result) (result != OMX_ErrorNone) #define SUCCEEDED(result) (result == OMX_ErrorNone) #define SWAPBYTES(ptrA, ptrB) { char t = *ptrA; *ptrA = *ptrB; *ptrB = t;} #define SIZE_NAL_FIELD_MAX 4 #define MDP_DEINTERLACE 0x80000000 #define ALLOCATE_BUFFER 0 #ifdef MAX_RES_720P #define PMEM_DEVICE "/dev/pmem_adsp" #elif MAX_RES_1080P_EBI #define PMEM_DEVICE "/dev/pmem_adsp" #elif MAX_RES_1080P #define PMEM_DEVICE "/dev/pmem_smipool" #endif //#define USE_EXTERN_PMEM_BUF /************************************************************************/ /* GLOBAL DECLARATIONS */ /************************************************************************/ #ifdef _ANDROID_ using namespace android; #endif #ifdef _MSM8974_ typedef unsigned short int uint16; const uint16 CRC_INIT = 0xFFFF ; const uint16 crc_16_l_table[ 256 ] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 }; #ifdef ANDROID_JELLYBEAN_MR1 //Since this is unavailable on Android 4.2.2, defining it in terms of base 10 static inline float log2f(const float& x) { return log(x) / log(2); } #endif /* fwrite doesn't necessarily write the entire buffer in one shot hence a helper * function to make sure the entire buffer is written */ size_t fwrite_helper(const void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t written = 0, to_write = size * nmemb; const char *ptr2 = (char *)ptr; while (written < to_write) { /* XXX: Ideally we'd like to do fwrite(..., size, 1, ...) as it makes * more sense, but fwrite(..., 1, size, ...) seems to give better perf. * for some reason. Seems contrary to what one would expect */ size_t temp = fwrite(ptr2 + written, 1, to_write - written, stream); if (!temp && ferror(stream)) { printf("Error while writing\n"); return temp; } written += temp; } return written; } uint16 crc_16_l_step_nv12 (uint16 seed, const void *buf_ptr, unsigned int byte_len, unsigned int height, unsigned int width) { uint16 crc_16 = ~seed; char *buf = (char *)buf_ptr; char *byte_ptr = buf; unsigned int i, j; const unsigned int width_align = 32; const unsigned int height_align = 32; unsigned int stride = (width + width_align -1) & (~(width_align-1)); unsigned int scan_lines = (height + height_align -1) & (~(height_align-1)); for (i = 0; i < height; i++) { for (j = 0; j < stride; j++) { if (j < width) { crc_16 = crc_16_l_table[ (crc_16 ^ *byte_ptr) & 0x00ff ] ^ (crc_16 >> 8); } byte_ptr++; } } byte_ptr = buf + (scan_lines * stride); for (i = scan_lines; i < scan_lines + height/2; i++) { for (j = 0; j < stride; j++) { if (j < width) { crc_16 = crc_16_l_table[ (crc_16 ^ *byte_ptr) & 0x00ff ] ^ (crc_16 >> 8); } byte_ptr++; } } return( ~crc_16 ); } #endif typedef enum { CODEC_FORMAT_H264 = 1, CODEC_FORMAT_MP4, CODEC_FORMAT_H263, CODEC_FORMAT_VC1, CODEC_FORMAT_DIVX, CODEC_FORMAT_MPEG2, #ifdef _MSM8974_ CODEC_FORMAT_VP8, CODEC_FORMAT_HEVC, CODEC_FORMAT_HEVC_HYBRID, CODEC_FORMAT_MVC, #endif CODEC_FORMAT_MAX } codec_format; typedef enum { FILE_TYPE_DAT_PER_AU = 1, FILE_TYPE_ARBITRARY_BYTES, FILE_TYPE_COMMON_CODEC_MAX, FILE_TYPE_START_OF_H264_SPECIFIC = 10, FILE_TYPE_264_NAL_SIZE_LENGTH = FILE_TYPE_START_OF_H264_SPECIFIC, FILE_TYPE_264_START_CODE_BASED, FILE_TYPE_START_OF_MP4_SPECIFIC = 20, FILE_TYPE_PICTURE_START_CODE = FILE_TYPE_START_OF_MP4_SPECIFIC, FILE_TYPE_START_OF_VC1_SPECIFIC = 30, FILE_TYPE_RCV = FILE_TYPE_START_OF_VC1_SPECIFIC, FILE_TYPE_VC1, FILE_TYPE_START_OF_DIVX_SPECIFIC = 40, FILE_TYPE_DIVX_4_5_6 = FILE_TYPE_START_OF_DIVX_SPECIFIC, FILE_TYPE_DIVX_311, FILE_TYPE_START_OF_MPEG2_SPECIFIC = 50, FILE_TYPE_MPEG2_START_CODE = FILE_TYPE_START_OF_MPEG2_SPECIFIC, #ifdef _MSM8974_ FILE_TYPE_START_OF_VP8_SPECIFIC = 60, FILE_TYPE_VP8_START_CODE = FILE_TYPE_START_OF_VP8_SPECIFIC, FILE_TYPE_VP8, FILE_TYPE_MVC = 5, #endif } file_type; typedef enum { GOOD_STATE = 0, PORT_SETTING_CHANGE_STATE, ERROR_STATE } test_status; typedef enum { FREE_HANDLE_AT_LOADED = 1, FREE_HANDLE_AT_IDLE, FREE_HANDLE_AT_EXECUTING, FREE_HANDLE_AT_PAUSE } freeHandle_test; struct temp_egl { int pmem_fd; int offset; }; static int (*Read_Buffer)(OMX_BUFFERHEADERTYPE *pBufHdr ); int inputBufferFileFd; FILE * outputBufferFile; #ifdef _MSM8974_ FILE * crcFile; #endif FILE * seqFile; int takeYuvLog = 0; int displayYuv = 0; int displayWindow = 0; int realtime_display = 0; int num_frames_to_decode = 0; int thumbnailMode = 0; Queue *etb_queue = NULL; Queue *fbd_queue = NULL; pthread_t ebd_thread_id; pthread_t fbd_thread_id; void* ebd_thread(void*); void* fbd_thread(void*); pthread_mutex_t etb_lock; pthread_mutex_t fbd_lock; pthread_mutex_t lock; pthread_cond_t cond; pthread_mutex_t eos_lock; pthread_cond_t eos_cond; pthread_mutex_t enable_lock; sem_t etb_sem; sem_t fbd_sem; sem_t seq_sem; sem_t in_flush_sem, out_flush_sem; OMX_PARAM_PORTDEFINITIONTYPE portFmt; OMX_PORT_PARAM_TYPE portParam; OMX_ERRORTYPE error; OMX_COLOR_FORMATTYPE color_fmt; static bool input_use_buffer = false,output_use_buffer = false; QOMX_VIDEO_DECODER_PICTURE_ORDER picture_order; #ifdef MAX_RES_1080P unsigned int color_fmt_type = 1; #else unsigned int color_fmt_type = 0; #endif #define CLR_KEY 0xe8fd #define COLOR_BLACK_RGBA_8888 0x00000000 #define FRAMEBUFFER_32 static int fb_fd = -1; static struct fb_var_screeninfo vinfo; static struct fb_fix_screeninfo finfo; static struct mdp_overlay overlay, *overlayp; static struct msmfb_overlay_data ov_front; static int vid_buf_front_id; static char tempbuf[16]; int overlay_fb(struct OMX_BUFFERHEADERTYPE *pBufHdr); void overlay_set(); void overlay_unset(); void render_fb(struct OMX_BUFFERHEADERTYPE *pBufHdr); int disable_output_port(); int enable_output_port(); int output_port_reconfig(); void free_output_buffers(); int open_display(); void close_display(); /************************************************************************/ /* GLOBAL INIT */ /************************************************************************/ int input_buf_cnt = 0; int height =0, width =0; int sliceheight = 0, stride = 0; int used_ip_buf_cnt = 0; unsigned free_op_buf_cnt = 0; volatile int event_is_done = 0; int ebd_cnt= 0, fbd_cnt = 0; int bInputEosReached = 0; int bOutputEosReached = 0; char in_filename[512]; #ifdef _MSM8974_ char crclogname[512]; #endif char seq_file_name[512]; unsigned char seq_enabled = 0; bool anti_flickering = true; unsigned char flush_input_progress = 0, flush_output_progress = 0; unsigned cmd_data = ~(unsigned)0, etb_count = 0; char curr_seq_command[100]; OMX_S64 timeStampLfile = 0; int fps = 30; unsigned int timestampInterval = 33333; codec_format codec_format_option; file_type file_type_option; freeHandle_test freeHandle_option; int nalSize = 0; int sent_disabled = 0; int waitForPortSettingsChanged = 1; test_status currentStatus = GOOD_STATE; struct timeval t_start = {0, 0}, t_end = {0, 0}; //* OMX Spec Version supported by the wrappers. Version = 1.1 */ const OMX_U32 CURRENT_OMX_SPEC_VERSION = 0x00000101; OMX_COMPONENTTYPE* dec_handle = 0; OMX_BUFFERHEADERTYPE **pInputBufHdrs = NULL; OMX_BUFFERHEADERTYPE **pOutYUVBufHdrs= NULL; static OMX_BOOL use_external_pmem_buf = OMX_FALSE; int rcv_v1=0; static struct temp_egl **p_eglHeaders = NULL; static unsigned use_buf_virt_addr[32]; OMX_QCOM_PLATFORM_PRIVATE_LIST *pPlatformList = NULL; OMX_QCOM_PLATFORM_PRIVATE_ENTRY *pPlatformEntry = NULL; OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; OMX_CONFIG_RECTTYPE crop_rect = {0, {{0, 0, 0, 0}}, 0, 0, 0, 0, 0}; static int bHdrflag = 0; /* Performance related variable*/ //QPERF_INIT(render_fb); //QPERF_INIT(client_decode); /************************************************************************/ /* GLOBAL FUNC DECL */ /************************************************************************/ int Init_Decoder(); int Play_Decoder(); int run_tests(); /**************************************************************************/ /* STATIC DECLARATIONS */ /**************************************************************************/ static int video_playback_count = 1; static int open_video_file (); static int Read_Buffer_From_DAT_File(OMX_BUFFERHEADERTYPE *pBufHdr ); static int Read_Buffer_From_H264_Start_Code_File(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_ArbitraryBytes(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_Vop_Start_Code_File(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_Mpeg2_Start_Code(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_Size_Nal(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_RCV_File_Seq_Layer(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_RCV_File(OMX_BUFFERHEADERTYPE *pBufHdr); #ifdef _MSM8974_ static int Read_Buffer_From_VP8_File(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_MVC_File(OMX_BUFFERHEADERTYPE *pBufHdr); #endif static int Read_Buffer_From_VC1_File(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_DivX_4_5_6_File(OMX_BUFFERHEADERTYPE *pBufHdr); static int Read_Buffer_From_DivX_311_File(OMX_BUFFERHEADERTYPE *pBufHdr); static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***pBufHdrs, OMX_U32 nPortIndex, long bufCntMin, long bufSize); static OMX_ERRORTYPE use_input_buffer(OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***bufferHdr, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufcnt); static OMX_ERRORTYPE use_output_buffer(OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***bufferHdr, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufcnt); static OMX_ERRORTYPE use_output_buffer_multiple_fd(OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***bufferHdr, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufcnt); static OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData); static OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer); static OMX_ERRORTYPE FillBufferDone(OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer); static void do_freeHandle_and_clean_up(bool isDueToError); #ifndef USE_ION static bool align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, OMX_U32 alignment); #endif void getFreePmem(); static int overlay_vsync_ctrl(int enable); static int clip2(int x) { x = x -1; x = x | x >> 1; x = x | x >> 2; x = x | x >> 4; x = x | x >> 16; x = x + 1; return x; } void wait_for_event(void) { DEBUG_PRINT("Waiting for event\n"); pthread_mutex_lock(&lock); while (event_is_done == 0) { pthread_cond_wait(&cond, &lock); } event_is_done = 0; pthread_mutex_unlock(&lock); DEBUG_PRINT("Running .... get the event\n"); } void event_complete(void ) { pthread_mutex_lock(&lock); if (event_is_done == 0) { event_is_done = 1; pthread_cond_broadcast(&cond); } pthread_mutex_unlock(&lock); } int get_next_command(FILE *seq_file) { int i = -1; do { i++; if (fread(&curr_seq_command[i], 1, 1, seq_file) != 1) return -1; } while (curr_seq_command[i] != '\n'); curr_seq_command[i] = 0; printf("\n cmd_str = %s", curr_seq_command); return 0; } int process_current_command(const char *seq_command) { char *data_str = NULL; unsigned int data = 0, bufCnt = 0, i = 0; int frameSize; if (strstr(seq_command, "pause") == seq_command) { printf("\n\n $$$$$ PAUSE $$$$$"); data_str = (char*)seq_command + strlen("pause") + 1; data = atoi(data_str); printf("\n After frame number %u", data); cmd_data = data; sem_wait(&seq_sem); if (!bOutputEosReached && !bInputEosReached) { printf("\n Sending PAUSE cmd to OMX compt"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StatePause,0); wait_for_event(); printf("\n EventHandler for PAUSE DONE"); } else seq_enabled = 0; } else if (strstr(seq_command, "sleep") == seq_command) { printf("\n\n $$$$$ SLEEP $$$$$"); data_str = (char*)seq_command + strlen("sleep") + 1; data = atoi(data_str); printf("\n Sleep Time = %u ms", data); usleep(data*1000); } else if (strstr(seq_command, "resume") == seq_command) { printf("\n\n $$$$$ RESUME $$$$$"); printf("\n Immediate effect"); printf("\n Sending RESUME cmd to OMX compt"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); wait_for_event(); printf("\n EventHandler for RESUME DONE"); } else if (strstr(seq_command, "flush") == seq_command) { printf("\n\n $$$$$ FLUSH $$$$$"); data_str = (char*)seq_command + strlen("flush") + 1; data = atoi(data_str); printf("\n After frame number %u", data); if (previous_vc1_au) { printf("\n Flush not allowed on Field boundary"); return 0; } cmd_data = data; sem_wait(&seq_sem); if (!bOutputEosReached && !bInputEosReached) { printf("\n Sending FLUSH cmd to OMX compt"); flush_input_progress = 1; flush_output_progress = 1; OMX_SendCommand(dec_handle, OMX_CommandFlush, OMX_ALL, 0); wait_for_event(); printf("\n EventHandler for FLUSH DONE"); printf("\n Post EBD_thread flush sem"); sem_post(&in_flush_sem); printf("\n Post FBD_thread flush sem"); sem_post(&out_flush_sem); } else seq_enabled = 0; } else if (strstr(seq_command, "disable_op") == seq_command) { printf("\n\n $$$$$ DISABLE OP PORT $$$$$"); data_str = (char*)seq_command + strlen("disable_op") + 1; data = atoi(data_str); printf("\n After frame number %u", data); cmd_data = data; sem_wait(&seq_sem); printf("\n Sending DISABLE OP cmd to OMX compt"); if (disable_output_port() != 0) { printf("\n ERROR: While DISABLE OP..."); do_freeHandle_and_clean_up(true); return -1; } else printf("\n EventHandler for DISABLE OP"); } else if (strstr(seq_command, "enable_op") == seq_command) { printf("\n\n $$$$$ ENABLE OP PORT $$$$$"); data_str = (char*)seq_command + strlen("enable_op") + 1; printf("\n Sending ENABLE OP cmd to OMX compt"); if (enable_output_port() != 0) { printf("\n ERROR: While ENABLE OP..."); do_freeHandle_and_clean_up(true); return -1; } else printf("\n EventHandler for ENABLE OP"); } else { printf("\n\n $$$$$ INVALID CMD $$$$$"); printf("\n seq_command[%s] is invalid", seq_command); seq_enabled = 0; } return 0; } void PrintFramePackArrangement(OMX_QCOM_FRAME_PACK_ARRANGEMENT framePackingArrangement) { if (framePackingArrangement.cancel_flag == 1) { /* Not worth printing out because the struct doesn't contain * valid or useful data */ return; } printf("id (%u)\n", (unsigned int)framePackingArrangement.id); printf("cancel_flag (%u)\n", (unsigned int)framePackingArrangement.cancel_flag); printf("type (%u)\n", (unsigned int)framePackingArrangement.type); printf("quincunx_sampling_flag (%u)\n", (unsigned int)framePackingArrangement.quincunx_sampling_flag); printf("content_interpretation_type (%u)\n", (unsigned int)framePackingArrangement.content_interpretation_type); printf("spatial_flipping_flag (%u)\n", (unsigned int)framePackingArrangement.spatial_flipping_flag); printf("frame0_flipped_flag (%u)\n", (unsigned int)framePackingArrangement.frame0_flipped_flag); printf("field_views_flag (%u)\n", (unsigned int)framePackingArrangement.field_views_flag); printf("current_frame_is_frame0_flag (%u)\n", (unsigned int)framePackingArrangement.current_frame_is_frame0_flag); printf("frame0_self_contained_flag (%u)\n", (unsigned int)framePackingArrangement.frame0_self_contained_flag); printf("frame1_self_contained_flag (%u)\n", (unsigned int)framePackingArrangement.frame1_self_contained_flag); printf("frame0_grid_position_x (%u)\n", (unsigned int)framePackingArrangement.frame0_grid_position_x); printf("frame0_grid_position_y (%u)\n", (unsigned int)framePackingArrangement.frame0_grid_position_y); printf("frame1_grid_position_x (%u)\n", (unsigned int)framePackingArrangement.frame1_grid_position_x); printf("frame1_grid_position_y (%u)\n", (unsigned int)framePackingArrangement.frame1_grid_position_y); printf("reserved_byte (%u)\n", (unsigned int)framePackingArrangement.reserved_byte); printf("repetition_period (%u)\n", (unsigned int)framePackingArrangement.repetition_period); printf("extension_flag (%u)\n", (unsigned int)framePackingArrangement.extension_flag); } void* ebd_thread(void* pArg) { int signal_eos = 0; while (currentStatus != ERROR_STATE) { int readBytes =0; OMX_BUFFERHEADERTYPE* pBuffer = NULL; if (flush_input_progress) { DEBUG_PRINT("\n EBD_thread flush wait start"); sem_wait(&in_flush_sem); DEBUG_PRINT("\n EBD_thread flush wait complete"); } sem_wait(&etb_sem); pthread_mutex_lock(&etb_lock); pBuffer = (OMX_BUFFERHEADERTYPE *) pop(etb_queue); pthread_mutex_unlock(&etb_lock); if (pBuffer == NULL) { DEBUG_PRINT_ERROR("Error - No etb pBuffer to dequeue\n"); continue; } if (num_frames_to_decode && (etb_count >= (unsigned int)num_frames_to_decode)) { printf("\n Signal EOS %d frames decoded \n", num_frames_to_decode); signal_eos = 1; } pBuffer->nOffset = 0; if (((readBytes = Read_Buffer(pBuffer)) > 0) && !signal_eos) { pBuffer->nFilledLen = readBytes; DEBUG_PRINT("%s: Timestamp sent(%lld)", __FUNCTION__, pBuffer->nTimeStamp); OMX_EmptyThisBuffer(dec_handle,pBuffer); etb_count++; } else { pBuffer->nFlags |= OMX_BUFFERFLAG_EOS; bInputEosReached = true; pBuffer->nFilledLen = readBytes; DEBUG_PRINT("%s: Timestamp sent(%lld)", __FUNCTION__, pBuffer->nTimeStamp); OMX_EmptyThisBuffer(dec_handle,pBuffer); DEBUG_PRINT("EBD::Either EOS or Some Error while reading file\n"); etb_count++; break; } } return NULL; } void* fbd_thread(void* pArg) { long unsigned act_time = 0, display_time = 0, render_time = 5e3, lipsync = 15e3; struct timeval t_avsync = {0, 0}, base_avsync = {0, 0}; float total_time = 0; int canDisplay = 1, contigous_drop_frame = 0, bytes_written = 0, ret = 0; OMX_S64 base_timestamp = 0, lastTimestamp = 0; OMX_BUFFERHEADERTYPE *pBuffer = NULL, *pPrevBuff = NULL; char value[PROPERTY_VALUE_MAX] = {0}; OMX_U32 aspectratio_prop = 0; pthread_mutex_lock(&eos_lock); #ifdef _MSM8974_ int stride,scanlines,stride_c,i; #endif DEBUG_PRINT("First Inside %s\n", __FUNCTION__); property_get("vidc.vdec.debug.aspectratio", value, "0"); aspectratio_prop = atoi(value); while (currentStatus != ERROR_STATE && !bOutputEosReached) { pthread_mutex_unlock(&eos_lock); DEBUG_PRINT("Inside %s\n", __FUNCTION__); if (flush_output_progress) { DEBUG_PRINT("\n FBD_thread flush wait start"); sem_wait(&out_flush_sem); DEBUG_PRINT("\n FBD_thread flush wait complete"); } sem_wait(&fbd_sem); pthread_mutex_lock(&enable_lock); if (sent_disabled) { pthread_mutex_unlock(&enable_lock); pthread_mutex_lock(&fbd_lock); if (pPrevBuff != NULL ) { if (push(fbd_queue, (void *)pBuffer)) DEBUG_PRINT_ERROR("Error in enqueueing fbd_data\n"); else sem_post(&fbd_sem); } pPrevBuff = NULL; pBuffer = NULL; if (free_op_buf_cnt == portFmt.nBufferCountActual) free_output_buffers(); pthread_mutex_unlock(&fbd_lock); pthread_mutex_lock(&eos_lock); continue; } pthread_mutex_unlock(&enable_lock); if (anti_flickering) pPrevBuff = pBuffer; pthread_mutex_lock(&fbd_lock); pBuffer = (OMX_BUFFERHEADERTYPE *)pop(fbd_queue); pthread_mutex_unlock(&fbd_lock); if (pBuffer == NULL) { if (anti_flickering) pBuffer = pPrevBuff; DEBUG_PRINT("Error - No pBuffer to dequeue\n"); pthread_mutex_lock(&eos_lock); continue; } else if (pBuffer->nFilledLen > 0) { if (!fbd_cnt) { gettimeofday(&t_start, NULL); } fbd_cnt++; DEBUG_PRINT("%s: fbd_cnt(%d) Buf(%p) Timestamp(%lld)", __FUNCTION__, fbd_cnt, pBuffer, pBuffer->nTimeStamp); canDisplay = 1; if (realtime_display) { if (pBuffer->nTimeStamp != (lastTimestamp + timestampInterval)) { DEBUG_PRINT("Unexpected timestamp[%lld]! Expected[%lld]\n", pBuffer->nTimeStamp, lastTimestamp + timestampInterval); } lastTimestamp = pBuffer->nTimeStamp; gettimeofday(&t_avsync, NULL); if (!base_avsync.tv_sec && !base_avsync.tv_usec) { display_time = 0; base_avsync = t_avsync; base_timestamp = pBuffer->nTimeStamp; DEBUG_PRINT("base_avsync Sec(%lu) uSec(%lu) base_timestamp(%lld)", base_avsync.tv_sec, base_avsync.tv_usec, base_timestamp); } else { act_time = (t_avsync.tv_sec - base_avsync.tv_sec) * 1e6 + t_avsync.tv_usec - base_avsync.tv_usec; display_time = pBuffer->nTimeStamp - base_timestamp; DEBUG_PRINT("%s: act_time(%lu) display_time(%lu)", __FUNCTION__, act_time, display_time); //Frame rcvd on time if (((act_time + render_time) >= (display_time - lipsync) && (act_time + render_time) <= (display_time + lipsync)) || //Display late frame (contigous_drop_frame > 5)) display_time = 0; else if ((act_time + render_time) < (display_time - lipsync)) //Delaying early frame display_time -= (lipsync + act_time + render_time); else { //Dropping late frame canDisplay = 0; contigous_drop_frame++; } } } if (displayYuv && canDisplay) { if (display_time) usleep(display_time); ret = overlay_fb(pBuffer); if (ret != 0) { printf("\nERROR in overlay_fb, disabling display!"); close_display(); displayYuv = 0; } usleep(render_time); contigous_drop_frame = 0; } if (takeYuvLog) { bytes_written = 0; if (color_fmt == (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m || color_fmt == (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView) { unsigned int i = 0; unsigned int nViewsDone = 0; unsigned int stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, portFmt.format.video.nFrameWidth); unsigned int scanlines = VENUS_Y_SCANLINES(COLOR_FMT_NV12, portFmt.format.video.nFrameHeight); char *frame_pos = (char *) pBuffer->pBuffer; char *view2 = color_fmt == (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView? (char *) pBuffer->pBuffer + VENUS_VIEW2_OFFSET(COLOR_FMT_NV12_MVTB, portFmt.format.video.nFrameWidth, portFmt.format.video.nFrameHeight): NULL; do { frame_pos += (stride * (int)crop_rect.nTop) + (int)crop_rect.nLeft; for (i = 0; i < crop_rect.nHeight; i++) { bytes_written += fwrite_helper(frame_pos, crop_rect.nWidth, 1, outputBufferFile); frame_pos += stride; } frame_pos = (nViewsDone == 0 ? (char *) pBuffer->pBuffer: view2) + stride * scanlines; frame_pos += (stride * (int)crop_rect.nTop) + (int)crop_rect.nLeft; for (i = 0; i < crop_rect.nHeight/2; i++) { bytes_written += fwrite_helper(frame_pos, crop_rect.nWidth, 1, outputBufferFile); frame_pos += stride; } nViewsDone++; if (view2 != NULL) { frame_pos = view2; } } while (view2 != NULL && nViewsDone < 2); } else { bytes_written = fwrite_helper((const char *)pBuffer->pBuffer, pBuffer->nFilledLen,1,outputBufferFile); } if (bytes_written < 0) { DEBUG_PRINT("\nFillBufferDone: Failed to write to the file\n"); } else { DEBUG_PRINT("\nFillBufferDone: Wrote %d YUV bytes to the file\n", bytes_written); } } #ifdef _MSM8974_ if (crcFile) { uint16 crc_val; crc_val = crc_16_l_step_nv12(CRC_INIT, pBuffer->pBuffer, pBuffer->nFilledLen, height, width); unsigned int num_bytes = fwrite_helper(&crc_val, 1, sizeof(crc_val), crcFile); if (num_bytes < sizeof(crc_val)) { printf("Failed to write CRC value into file\n"); } } #endif if (pBuffer->nFlags & OMX_BUFFERFLAG_EXTRADATA) { OMX_OTHER_EXTRADATATYPE *pExtra; DEBUG_PRINT_ERROR(">> BUFFER WITH EXTRA DATA RCVD <<<"); pExtra = (OMX_OTHER_EXTRADATATYPE *) ((unsigned)(pBuffer->pBuffer + pBuffer->nOffset + pBuffer->nFilledLen + 3)&(~3)); while (pExtra && (OMX_U8*)pExtra < (pBuffer->pBuffer + pBuffer->nAllocLen) && pExtra->eType != OMX_ExtraDataNone ) { DEBUG_PRINT("ExtraData : pBuf(%p) BufTS(%lld) Type(%x) DataSz(%u)", pBuffer, pBuffer->nTimeStamp, pExtra->eType, pExtra->nDataSize); switch ((int)pExtra->eType) { case OMX_ExtraDataInterlaceFormat: { OMX_STREAMINTERLACEFORMAT *pInterlaceFormat = (OMX_STREAMINTERLACEFORMAT *)pExtra->data; DEBUG_PRINT("OMX_ExtraDataInterlaceFormat: Buf(%p) TSmp(%lld) IntPtr(%p) Fmt(%x)", pBuffer->pBuffer, pBuffer->nTimeStamp, pInterlaceFormat, pInterlaceFormat->nInterlaceFormats); break; } case OMX_ExtraDataFrameInfo: { OMX_QCOM_EXTRADATA_FRAMEINFO *frame_info = (OMX_QCOM_EXTRADATA_FRAMEINFO *)pExtra->data; DEBUG_PRINT_ERROR("OMX_ExtraDataFrameInfo: Buf(%p) TSmp(%lld) PicType(%u) IntT(%d) ConMB(%u)", pBuffer->pBuffer, pBuffer->nTimeStamp, frame_info->ePicType, frame_info->interlaceType, (unsigned int)frame_info->nConcealedMacroblocks); if (aspectratio_prop) DEBUG_PRINT_ERROR(" FrmRate(%u), AspRatioX(%u), AspRatioY(%u) DispWidth(%u) DispHeight(%u)", (unsigned int)frame_info->nFrameRate, (unsigned int)frame_info->aspectRatio.aspectRatioX, (unsigned int)frame_info->aspectRatio.aspectRatioY, (unsigned int)frame_info->displayAspectRatio.displayHorizontalSize, (unsigned int)frame_info->displayAspectRatio.displayVerticalSize); else DEBUG_PRINT_ERROR(" FrmRate(%u), AspRatioX(%u), AspRatioY(%u) DispWidth(%u) DispHeight(%u)", (unsigned int)frame_info->nFrameRate, (unsigned int)frame_info->aspectRatio.aspectRatioX, (unsigned int)frame_info->aspectRatio.aspectRatioY, (unsigned int)frame_info->displayAspectRatio.displayHorizontalSize, (unsigned int)frame_info->displayAspectRatio.displayVerticalSize); DEBUG_PRINT_ERROR("PANSCAN numWindows(%u)", (unsigned int)frame_info->panScan.numWindows); for (unsigned int i = 0; i < frame_info->panScan.numWindows; i++) { DEBUG_PRINT_ERROR("WINDOW Lft(%d) Tp(%d) Rgt(%d) Bttm(%d)", (int)frame_info->panScan.window[i].x, (int)frame_info->panScan.window[i].y, (int)frame_info->panScan.window[i].dx, (int)frame_info->panScan.window[i].dy); } break; } break; case OMX_ExtraDataConcealMB: { OMX_U8 data = 0, *data_ptr = (OMX_U8 *)pExtra->data; OMX_U32 concealMBnum = 0, bytes_cnt = 0; while (bytes_cnt < pExtra->nDataSize) { data = *data_ptr; while (data) { concealMBnum += (data&0x01); data >>= 1; } data_ptr++; bytes_cnt++; } DEBUG_PRINT_ERROR("OMX_ExtraDataConcealMB: Buf(%p) TSmp(%lld) ConcealMB(%u)", pBuffer->pBuffer, pBuffer->nTimeStamp, (unsigned int)concealMBnum); } break; case OMX_ExtraDataMP2ExtnData: { DEBUG_PRINT_ERROR("\nOMX_ExtraDataMP2ExtnData"); OMX_U8 data = 0, *data_ptr = (OMX_U8 *)pExtra->data; OMX_U32 bytes_cnt = 0; while (bytes_cnt < pExtra->nDataSize) { DEBUG_PRINT_ERROR("\n MPEG-2 Extension Data Values[%u] = 0x%x", (unsigned int)bytes_cnt, *data_ptr); data_ptr++; bytes_cnt++; } } break; case OMX_ExtraDataMP2UserData: { DEBUG_PRINT_ERROR("\nOMX_ExtraDataMP2UserData"); OMX_U8 data = 0, *data_ptr = (OMX_U8 *)pExtra->data; OMX_U32 bytes_cnt = 0; while (bytes_cnt < pExtra->nDataSize) { DEBUG_PRINT_ERROR("\n MPEG-2 User Data Values[%u] = 0x%x", (unsigned int)bytes_cnt, *data_ptr); data_ptr++; bytes_cnt++; } } break; case OMX_ExtraDataQP: { DEBUG_PRINT("\nOMX_ExtraDataQP\n"); OMX_QCOM_EXTRADATA_QP *qp_info = (OMX_QCOM_EXTRADATA_QP *)pExtra->data; DEBUG_PRINT("Input frame QP = %lu\n", qp_info->nQP); } break; case OMX_ExtraDataInputBitsInfo: { DEBUG_PRINT("\nOMX_ExtraDataInputBitsInfo\n"); OMX_QCOM_EXTRADATA_BITS_INFO *bits_info = (OMX_QCOM_EXTRADATA_BITS_INFO *)pExtra->data; DEBUG_PRINT("Input header bits size = %lu\n", bits_info->header_bits); DEBUG_PRINT("Input frame bits size = %lu\n", bits_info->frame_bits); } break; default: DEBUG_PRINT_ERROR("Unknown Extrata!"); } if (pExtra->nSize < (pBuffer->nAllocLen - (OMX_U32)pExtra)) pExtra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) pExtra) + pExtra->nSize); else { DEBUG_PRINT_ERROR("ERROR: Extradata pointer overflow buffer(%p) extra(%p)", pBuffer, pExtra); pExtra = NULL; } } } } if (pBuffer->nFlags & QOMX_VIDEO_BUFFERFLAG_EOSEQ) { DEBUG_PRINT("\n"); DEBUG_PRINT("***************************************************\n"); DEBUG_PRINT("FillBufferDone: End Of Sequence Received\n"); DEBUG_PRINT("***************************************************\n"); } if (pBuffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT) { DEBUG_PRINT("\n"); DEBUG_PRINT("***************************************************\n"); DEBUG_PRINT("FillBufferDone: OMX_BUFFERFLAG_DATACORRUPT Received\n"); DEBUG_PRINT("***************************************************\n"); } /********************************************************************/ /* De-Initializing the open max and relasing the buffers and */ /* closing the files.*/ /********************************************************************/ if (pBuffer->nFlags & OMX_BUFFERFLAG_EOS ) { OMX_QCOM_FRAME_PACK_ARRANGEMENT framePackingArrangement; OMX_GetConfig(dec_handle, (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoFramePackingArrangement, &framePackingArrangement); PrintFramePackArrangement(framePackingArrangement); gettimeofday(&t_end, NULL); total_time = ((float) ((t_end.tv_sec - t_start.tv_sec) * 1e6 + t_end.tv_usec - t_start.tv_usec))/ 1e6; //total frames is fbd_cnt - 1 since the start time is //recorded after the first frame is decoded. printf("\nAvg decoding frame rate=%f\n", (fbd_cnt - 1)/total_time); DEBUG_PRINT("***************************************************\n"); DEBUG_PRINT("FillBufferDone: End Of Stream Reached\n"); DEBUG_PRINT("***************************************************\n"); pthread_mutex_lock(&eos_lock); bOutputEosReached = true; break; } pthread_mutex_lock(&enable_lock); if (flush_output_progress || sent_disabled) { pBuffer->nFilledLen = 0; pBuffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA; pthread_mutex_lock(&fbd_lock); if ( pPrevBuff != NULL ) { if (push(fbd_queue, (void *)pPrevBuff)) DEBUG_PRINT_ERROR("Error in enqueueing fbd_data\n"); else sem_post(&fbd_sem); pPrevBuff = NULL; } if (push(fbd_queue, (void *)pBuffer) < 0) { DEBUG_PRINT_ERROR("Error in enqueueing fbd_data\n"); } else sem_post(&fbd_sem); pthread_mutex_unlock(&fbd_lock); } else { if (!anti_flickering) pPrevBuff = pBuffer; if (pPrevBuff) { pthread_mutex_lock(&fbd_lock); pthread_mutex_lock(&eos_lock); if (!bOutputEosReached) { if ( OMX_FillThisBuffer(dec_handle, pPrevBuff) == OMX_ErrorNone ) { free_op_buf_cnt--; } } pthread_mutex_unlock(&eos_lock); pthread_mutex_unlock(&fbd_lock); } } pthread_mutex_unlock(&enable_lock); if (cmd_data <= (unsigned)fbd_cnt) { sem_post(&seq_sem); printf("\n Posted seq_sem Frm(%d) Req(%d)", fbd_cnt, cmd_data); cmd_data = ~(unsigned)0; } pthread_mutex_lock(&eos_lock); } if (seq_enabled) { seq_enabled = 0; sem_post(&seq_sem); printf("\n Posted seq_sem in EOS \n"); } pthread_cond_broadcast(&eos_cond); pthread_mutex_unlock(&eos_lock); return NULL; } OMX_ERRORTYPE EventHandler(OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_EVENTTYPE eEvent, OMX_IN OMX_U32 nData1, OMX_IN OMX_U32 nData2, OMX_IN OMX_PTR pEventData) { DEBUG_PRINT("Function %s \n", __FUNCTION__); switch (eEvent) { case OMX_EventCmdComplete: DEBUG_PRINT("\n OMX_EventCmdComplete \n"); if (OMX_CommandPortDisable == (OMX_COMMANDTYPE)nData1) { DEBUG_PRINT("*********************************************\n"); DEBUG_PRINT("Recieved DISABLE Event Command Complete[%d]\n",nData2); DEBUG_PRINT("*********************************************\n"); } else if (OMX_CommandPortEnable == (OMX_COMMANDTYPE)nData1) { DEBUG_PRINT("*********************************************\n"); DEBUG_PRINT("Recieved ENABLE Event Command Complete[%d]\n",nData2); DEBUG_PRINT("*********************************************\n"); if (currentStatus == PORT_SETTING_CHANGE_STATE) currentStatus = GOOD_STATE; pthread_mutex_lock(&enable_lock); sent_disabled = 0; pthread_mutex_unlock(&enable_lock); } else if (OMX_CommandFlush == (OMX_COMMANDTYPE)nData1) { DEBUG_PRINT("*********************************************\n"); DEBUG_PRINT("Received FLUSH Event Command Complete[%d]\n",nData2); DEBUG_PRINT("*********************************************\n"); if (nData2 == 0) flush_input_progress = 0; else if (nData2 == 1) flush_output_progress = 0; } if (!flush_input_progress && !flush_output_progress) event_complete(); break; case OMX_EventError: printf("*********************************************\n"); printf("Received OMX_EventError Event Command !\n"); printf("*********************************************\n"); currentStatus = ERROR_STATE; if (OMX_ErrorInvalidState == (OMX_ERRORTYPE)nData1 || OMX_ErrorHardware == (OMX_ERRORTYPE)nData1) { printf("Invalid State or hardware error \n"); if (event_is_done == 0) { DEBUG_PRINT("Event error in the middle of Decode \n"); pthread_mutex_lock(&eos_lock); bOutputEosReached = true; pthread_mutex_unlock(&eos_lock); if (seq_enabled) { seq_enabled = 0; sem_post(&seq_sem); printf("\n Posted seq_sem in ERROR"); } event_complete(); } } if (waitForPortSettingsChanged) { waitForPortSettingsChanged = 0; event_complete(); } sem_post(&etb_sem); sem_post(&fbd_sem); break; case OMX_EventPortSettingsChanged: DEBUG_PRINT("OMX_EventPortSettingsChanged port[%d]\n", nData1); if (nData2 == OMX_IndexConfigCommonOutputCrop) { OMX_U32 outPortIndex = 1; if (nData1 == outPortIndex) { crop_rect.nPortIndex = outPortIndex; OMX_ERRORTYPE ret = OMX_GetConfig(dec_handle, OMX_IndexConfigCommonOutputCrop, &crop_rect); if (FAILED(ret)) { DEBUG_PRINT_ERROR("Failed to get crop rectangle\n"); break; } else DEBUG_PRINT("Got Crop Rect: (%d, %d) (%d x %d)\n", crop_rect.nLeft, crop_rect.nTop, crop_rect.nWidth, crop_rect.nHeight); } currentStatus = GOOD_STATE; break; } #ifdef _MSM8974_ if (nData2 != OMX_IndexParamPortDefinition) break; #endif currentStatus = PORT_SETTING_CHANGE_STATE; if (waitForPortSettingsChanged) { waitForPortSettingsChanged = 0; event_complete(); } else { pthread_mutex_lock(&eos_lock); pthread_cond_broadcast(&eos_cond); pthread_mutex_unlock(&eos_lock); } break; case OMX_EventBufferFlag: DEBUG_PRINT("OMX_EventBufferFlag port[%d] flags[%x]\n", nData1, nData2); #if 0 // we should not set the bOutputEosReached here. in stead we wait until fbd_thread to // check the flag so that all frames can be dumped for bit exactness check. if (nData1 == 1 && (nData2 & OMX_BUFFERFLAG_EOS)) { pthread_mutex_lock(&eos_lock); bOutputEosReached = true; pthread_mutex_unlock(&eos_lock); if (seq_enabled) { seq_enabled = 0; sem_post(&seq_sem); printf("\n Posted seq_sem in OMX_EventBufferFlag"); } } else { DEBUG_PRINT_ERROR("OMX_EventBufferFlag Event not handled\n"); } #endif break; case OMX_EventIndexsettingChanged: DEBUG_PRINT("OMX_EventIndexSettingChanged Interlace mode[%x]\n", nData1); break; default: DEBUG_PRINT_ERROR("ERROR - Unknown Event \n"); break; } return OMX_ErrorNone; } OMX_ERRORTYPE EmptyBufferDone(OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { int readBytes =0; int bufCnt=0; OMX_ERRORTYPE result; DEBUG_PRINT("Function %s cnt[%d]\n", __FUNCTION__, ebd_cnt); ebd_cnt++; if (bInputEosReached) { DEBUG_PRINT("*****EBD:Input EoS Reached************\n"); return OMX_ErrorNone; } pthread_mutex_lock(&etb_lock); if (push(etb_queue, (void *) pBuffer) < 0) { DEBUG_PRINT_ERROR("Error in enqueue ebd data\n"); return OMX_ErrorUndefined; } pthread_mutex_unlock(&etb_lock); sem_post(&etb_sem); return OMX_ErrorNone; } OMX_ERRORTYPE FillBufferDone(OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) { DEBUG_PRINT("Inside %s callback_count[%d] \n", __FUNCTION__, fbd_cnt); /* Test app will assume there is a dynamic port setting * In case that there is no dynamic port setting, OMX will not call event cb, * instead OMX will send empty this buffer directly and we need to clear an event here */ if (waitForPortSettingsChanged) { waitForPortSettingsChanged = 0; if (displayYuv) overlay_set(); event_complete(); } pthread_mutex_lock(&fbd_lock); free_op_buf_cnt++; if (push(fbd_queue, (void *)pBuffer) < 0) { pthread_mutex_unlock(&fbd_lock); DEBUG_PRINT_ERROR("Error in enqueueing fbd_data\n"); return OMX_ErrorUndefined; } pthread_mutex_unlock(&fbd_lock); sem_post(&fbd_sem); return OMX_ErrorNone; } int main(int argc, char **argv) { int i=0; int bufCnt=0; int num=0; int outputOption = 0; int test_option = 0; int pic_order = 0; OMX_ERRORTYPE result; sliceheight = height = 144; stride = width = 176; crop_rect.nLeft = 0; crop_rect.nTop = 0; crop_rect.nWidth = width; crop_rect.nHeight = height; if (argc < 2) { printf("To use it: ./mm-vdec-omx-test \n"); printf("Command line argument is also available\n"); return -1; } strlcpy(in_filename, argv[1], strlen(argv[1])+1); #ifdef _MSM8974_ strlcpy(crclogname, argv[1], strlen(argv[1])+1); strcat(crclogname, ".crc"); #endif if (argc > 2) { codec_format_option = (codec_format)atoi(argv[2]); // file_type, out_op, tst_op, nal_sz, disp_win, rt_dis, (fps), color, pic_order, num_frames_to_decode int param[10] = {2, 1, 1, 0, 0, 0, 0xFF, 0xFF, 0xFF, 0xFF}; int next_arg = 3, idx = 0; while (argc > next_arg && idx < 10) { if (strlen(argv[next_arg]) > 2) { strlcpy(seq_file_name, argv[next_arg],strlen(argv[next_arg]) + 1); next_arg = argc; } else param[idx++] = atoi(argv[next_arg++]); } idx = 0; file_type_option = (file_type)param[idx++]; if (codec_format_option == CODEC_FORMAT_H264 && file_type_option == 3) { nalSize = param[idx++]; if (nalSize != 2 && nalSize != 4) { printf("Error - Can't pass NAL length size = %d\n", nalSize); return -1; } } outputOption = param[idx++]; test_option = param[idx++]; if ((outputOption == 1 || outputOption ==3) && test_option != 3) { displayWindow = param[idx++]; if (displayWindow > 0) printf("Only entire display window supported! Ignoring value\n"); realtime_display = param[idx++]; } if (realtime_display) { takeYuvLog = 0; if (param[idx] != 0xFF) { fps = param[idx++]; timestampInterval = 1e6 / fps; } } color_fmt_type = (param[idx] != 0xFF)? param[idx++] : color_fmt_type; if (test_option != 3) { pic_order = (param[idx] != 0xFF)? param[idx++] : 0; num_frames_to_decode = param[idx++]; } printf("Executing DynPortReconfig QCIF 144 x 176 \n"); } else { printf("Command line argument is available\n"); printf("To use it: ./mm-vdec-omx-test \n"); printf(" \n"); printf(" \n\n\n"); printf(" *********************************************\n"); printf(" ENTER THE TEST CASE YOU WOULD LIKE TO EXECUTE\n"); printf(" *********************************************\n"); printf(" 1--> H264\n"); printf(" 2--> MP4\n"); printf(" 3--> H263\n"); printf(" 4--> VC1\n"); printf(" 5--> DivX\n"); printf(" 6--> MPEG2\n"); #ifdef _MSM8974_ printf(" 7--> VP8\n"); printf(" 8--> HEVC\n"); printf(" 9--> HYBRID\n"); printf(" 10-> MVC\n"); #endif fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",(int *)&codec_format_option); fflush(stdin); if (codec_format_option > CODEC_FORMAT_MAX) { printf(" Wrong test case...[%d] \n", codec_format_option); return -1; } printf(" *********************************************\n"); printf(" ENTER THE TEST CASE YOU WOULD LIKE TO EXECUTE\n"); printf(" *********************************************\n"); printf(" 1--> PER ACCESS UNIT CLIP (.dat). Clip only available for H264 and Mpeg4\n"); printf(" 2--> ARBITRARY BYTES (need .264/.264c/.m4v/.263/.rcv/.vc1/.m2v)\n"); if (codec_format_option == CODEC_FORMAT_H264) { printf(" 3--> NAL LENGTH SIZE CLIP (.264c)\n"); printf(" 4--> START CODE BASED CLIP (.264/.h264)\n"); } else if ( (codec_format_option == CODEC_FORMAT_MP4) || (codec_format_option == CODEC_FORMAT_H263) ) { printf(" 3--> MP4 VOP or H263 P0 SHORT HEADER START CODE CLIP (.m4v or .263)\n"); } else if (codec_format_option == CODEC_FORMAT_VC1) { printf(" 3--> VC1 clip Simple/Main Profile (.rcv)\n"); printf(" 4--> VC1 clip Advance Profile (.vc1)\n"); } else if (codec_format_option == CODEC_FORMAT_DIVX) { printf(" 3--> DivX 4, 5, 6 clip (.cmp)\n"); #ifdef MAX_RES_1080P printf(" 4--> DivX 3.11 clip \n"); #endif } else if (codec_format_option == CODEC_FORMAT_MPEG2) { printf(" 3--> MPEG2 START CODE CLIP (.m2v)\n"); } #ifdef _MSM8974_ else if (codec_format_option == CODEC_FORMAT_MVC) { printf(" 5--> MVC clip (.264)\n"); } else if (codec_format_option == CODEC_FORMAT_VP8) { printf(" 61--> VP8 START CODE CLIP (.ivf)\n"); } #endif fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",(int *)&file_type_option); #ifdef _MSM8974_ if (codec_format_option == CODEC_FORMAT_VP8) { file_type_option = FILE_TYPE_VP8; } else if (codec_format_option == CODEC_FORMAT_MVC) { file_type_option = FILE_TYPE_MVC; } #endif fflush(stdin); if (codec_format_option == CODEC_FORMAT_H264 && file_type_option == 3) { printf(" Enter Nal length size [2 or 4] \n"); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&nalSize); if (nalSize != 2 && nalSize != 4) { printf("Error - Can't pass NAL length size = %d\n", nalSize); return -1; } } printf(" *********************************************\n"); printf(" Output buffer option:\n"); printf(" *********************************************\n"); printf(" 0 --> No display and no YUV log\n"); printf(" 1 --> Diplay YUV\n"); printf(" 2 --> Take YUV log\n"); printf(" 3 --> Display YUV and take YUV log\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",(int *)&outputOption); fflush(stdin); printf(" *********************************************\n"); printf(" ENTER THE TEST CASE YOU WOULD LIKE TO EXECUTE\n"); printf(" *********************************************\n"); printf(" 1 --> Play the clip till the end\n"); printf(" 2 --> Run compliance test. Do NOT expect any display for most option. \n"); printf(" Please only see \"TEST SUCCESSFULL\" to indicate test pass\n"); printf(" 3 --> Thumbnail decode mode\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&test_option); fflush(stdin); if (test_option == 3) thumbnailMode = 1; if ((outputOption == 1 || outputOption == 3) && thumbnailMode == 0) { printf(" *********************************************\n"); printf(" ENTER THE PORTION OF DISPLAY TO USE\n"); printf(" *********************************************\n"); printf(" 0 --> Entire Screen\n"); printf(" 1 --> 1/4 th of the screen starting from top left corner to middle \n"); printf(" 2 --> 1/4 th of the screen starting from middle to top right corner \n"); printf(" 3 --> 1/4 th of the screen starting from middle to bottom left \n"); printf(" 4 --> 1/4 th of the screen starting from middle to bottom right \n"); printf(" Please only see \"TEST SUCCESSFULL\" to indidcate test pass\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&displayWindow); fflush(stdin); if (displayWindow > 0) { printf(" Curently display window 0 only supported; ignoring other values\n"); displayWindow = 0; } } if ((outputOption == 1 || outputOption == 3) && thumbnailMode == 0) { printf(" *********************************************\n"); printf(" DO YOU WANT TEST APP TO RENDER in Real time \n"); printf(" 0 --> NO\n 1 --> YES\n"); printf(" Warning: For H264, it require one NAL per frame clip.\n"); printf(" For Arbitrary bytes option, Real time display is not recommended\n"); printf(" *********************************************\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&realtime_display); fflush(stdin); } if (realtime_display) { printf(" *********************************************\n"); printf(" ENTER THE CLIP FPS\n"); printf(" Exception: Timestamp extracted from clips will be used.\n"); printf(" *********************************************\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&fps); fflush(stdin); timestampInterval = 1000000/fps; } printf(" *********************************************\n"); printf(" ENTER THE COLOR FORMAT \n"); printf(" 0 --> Semiplanar \n 1 --> Tile Mode\n"); printf(" *********************************************\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&color_fmt_type); fflush(stdin); if (thumbnailMode != 1) { printf(" *********************************************\n"); printf(" Output picture order option: \n"); printf(" *********************************************\n"); printf(" 0 --> Display order\n 1 --> Decode order\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&pic_order); fflush(stdin); printf(" *********************************************\n"); printf(" Number of frames to decode: \n"); printf(" 0 ---> decode all frames: \n"); printf(" *********************************************\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",&num_frames_to_decode); fflush(stdin); } } if (file_type_option >= FILE_TYPE_COMMON_CODEC_MAX) { switch (codec_format_option) { case CODEC_FORMAT_H264: file_type_option = (file_type)(FILE_TYPE_START_OF_H264_SPECIFIC + file_type_option - FILE_TYPE_COMMON_CODEC_MAX); break; case CODEC_FORMAT_DIVX: file_type_option = (file_type)(FILE_TYPE_START_OF_DIVX_SPECIFIC + file_type_option - FILE_TYPE_COMMON_CODEC_MAX); break; case CODEC_FORMAT_MP4: case CODEC_FORMAT_H263: file_type_option = (file_type)(FILE_TYPE_START_OF_MP4_SPECIFIC + file_type_option - FILE_TYPE_COMMON_CODEC_MAX); break; case CODEC_FORMAT_VC1: file_type_option = (file_type)(FILE_TYPE_START_OF_VC1_SPECIFIC + file_type_option - FILE_TYPE_COMMON_CODEC_MAX); break; case CODEC_FORMAT_MPEG2: file_type_option = (file_type)(FILE_TYPE_START_OF_MPEG2_SPECIFIC + file_type_option - FILE_TYPE_COMMON_CODEC_MAX); break; #ifdef _MSM8974_ case CODEC_FORMAT_VP8: case CODEC_FORMAT_MVC: break; #endif default: printf("Error: Unknown code %d\n", codec_format_option); } } CONFIG_VERSION_SIZE(picture_order); picture_order.eOutputPictureOrder = QOMX_VIDEO_DISPLAY_ORDER; if (pic_order == 1) picture_order.eOutputPictureOrder = QOMX_VIDEO_DECODE_ORDER; if (outputOption == 0) { displayYuv = 0; takeYuvLog = 0; realtime_display = 0; } else if (outputOption == 1) { displayYuv = 1; } else if (outputOption == 2) { takeYuvLog = 1; realtime_display = 0; } else if (outputOption == 3) { displayYuv = 1; takeYuvLog = !realtime_display; } else { printf("Wrong option. Assume you want to see the YUV display\n"); displayYuv = 1; } if (test_option == 2) { printf(" *********************************************\n"); printf(" ENTER THE COMPLIANCE TEST YOU WOULD LIKE TO EXECUTE\n"); printf(" *********************************************\n"); printf(" 1 --> Call Free Handle at the OMX_StateLoaded\n"); printf(" 2 --> Call Free Handle at the OMX_StateIdle\n"); printf(" 3 --> Call Free Handle at the OMX_StateExecuting\n"); printf(" 4 --> Call Free Handle at the OMX_StatePause\n"); fflush(stdin); fgets(tempbuf,sizeof(tempbuf),stdin); sscanf(tempbuf,"%d",(int *)&freeHandle_option); fflush(stdin); } else { freeHandle_option = (freeHandle_test)0; } printf("Input values: inputfilename[%s]\n", in_filename); printf("*******************************************************\n"); pthread_cond_init(&cond, 0); pthread_cond_init(&eos_cond, 0); pthread_mutex_init(&eos_lock, 0); pthread_mutex_init(&lock, 0); pthread_mutex_init(&etb_lock, 0); pthread_mutex_init(&fbd_lock, 0); pthread_mutex_init(&enable_lock, 0); if (-1 == sem_init(&etb_sem, 0, 0)) { printf("Error - sem_init failed %d\n", errno); } if (-1 == sem_init(&fbd_sem, 0, 0)) { printf("Error - sem_init failed %d\n", errno); } if (-1 == sem_init(&seq_sem, 0, 0)) { printf("Error - sem_init failed %d\n", errno); } if (-1 == sem_init(&in_flush_sem, 0, 0)) { printf("Error - sem_init failed %d\n", errno); } if (-1 == sem_init(&out_flush_sem, 0, 0)) { printf("Error - sem_init failed %d\n", errno); } etb_queue = alloc_queue(); if (etb_queue == NULL) { printf("\n Error in Creating etb_queue\n"); return -1; } fbd_queue = alloc_queue(); if (fbd_queue == NULL) { printf("\n Error in Creating fbd_queue\n"); free_queue(etb_queue); return -1; } if (0 != pthread_create(&fbd_thread_id, NULL, fbd_thread, NULL)) { printf("\n Error in Creating fbd_thread \n"); free_queue(etb_queue); free_queue(fbd_queue); return -1; } if (displayYuv) { if (open_display() != 0) { printf("\n Error opening display! Video won't be displayed..."); displayYuv = 0; } } run_tests(); pthread_cond_destroy(&cond); pthread_mutex_destroy(&lock); pthread_mutex_destroy(&etb_lock); pthread_mutex_destroy(&fbd_lock); pthread_mutex_destroy(&enable_lock); pthread_cond_destroy(&eos_cond); pthread_mutex_destroy(&eos_lock); if (-1 == sem_destroy(&etb_sem)) { DEBUG_PRINT_ERROR("Error - sem_destroy failed %d\n", errno); } if (-1 == sem_destroy(&fbd_sem)) { DEBUG_PRINT_ERROR("Error - sem_destroy failed %d\n", errno); } if (-1 == sem_destroy(&seq_sem)) { DEBUG_PRINT_ERROR("Error - sem_destroy failed %d\n", errno); } if (-1 == sem_destroy(&in_flush_sem)) { DEBUG_PRINT_ERROR("Error - sem_destroy failed %d\n", errno); } if (-1 == sem_destroy(&out_flush_sem)) { DEBUG_PRINT_ERROR("Error - sem_destroy failed %d\n", errno); } if (displayYuv) close_display(); return 0; } int run_tests() { int cmd_error = 0; DEBUG_PRINT("Inside %s\n", __FUNCTION__); waitForPortSettingsChanged = 1; if (file_type_option == FILE_TYPE_DAT_PER_AU) { Read_Buffer = Read_Buffer_From_DAT_File; } else if (file_type_option == FILE_TYPE_ARBITRARY_BYTES) { Read_Buffer = Read_Buffer_ArbitraryBytes; } else if (codec_format_option == CODEC_FORMAT_H264) { if (file_type_option == FILE_TYPE_264_NAL_SIZE_LENGTH) { Read_Buffer = Read_Buffer_From_Size_Nal; } else if (file_type_option == FILE_TYPE_264_START_CODE_BASED) { Read_Buffer = Read_Buffer_From_H264_Start_Code_File; } else { DEBUG_PRINT_ERROR("Invalid file_type_option(%d) for H264", file_type_option); return -1; } } else if ((codec_format_option == CODEC_FORMAT_H263) || (codec_format_option == CODEC_FORMAT_MP4)) { Read_Buffer = Read_Buffer_From_Vop_Start_Code_File; } else if (codec_format_option == CODEC_FORMAT_MPEG2) { Read_Buffer = Read_Buffer_From_Mpeg2_Start_Code; } else if (file_type_option == FILE_TYPE_DIVX_4_5_6) { Read_Buffer = Read_Buffer_From_DivX_4_5_6_File; } #ifdef MAX_RES_1080P else if (file_type_option == FILE_TYPE_DIVX_311) { Read_Buffer = Read_Buffer_From_DivX_311_File; } #endif else if (file_type_option == FILE_TYPE_RCV) { Read_Buffer = Read_Buffer_From_RCV_File; } #ifdef _MSM8974_ else if (file_type_option == FILE_TYPE_VP8) { Read_Buffer = Read_Buffer_From_VP8_File; } else if (codec_format_option == CODEC_FORMAT_MVC) { Read_Buffer = Read_Buffer_From_MVC_File; } #endif else if (file_type_option == FILE_TYPE_VC1) { Read_Buffer = Read_Buffer_From_VC1_File; } DEBUG_PRINT("file_type_option %d!\n", file_type_option); switch (file_type_option) { case FILE_TYPE_DAT_PER_AU: case FILE_TYPE_ARBITRARY_BYTES: case FILE_TYPE_264_START_CODE_BASED: case FILE_TYPE_264_NAL_SIZE_LENGTH: case FILE_TYPE_PICTURE_START_CODE: case FILE_TYPE_MPEG2_START_CODE: case FILE_TYPE_RCV: case FILE_TYPE_VC1: #ifdef _MSM8974_ case FILE_TYPE_VP8: case FILE_TYPE_MVC: #endif case FILE_TYPE_DIVX_4_5_6: #ifdef MAX_RES_1080P case FILE_TYPE_DIVX_311: #endif if (Init_Decoder()!= 0x00) { DEBUG_PRINT_ERROR("Error - Decoder Init failed\n"); return -1; } if (Play_Decoder() != 0x00) { return -1; } break; default: DEBUG_PRINT_ERROR("Error - Invalid Entry...%d\n",file_type_option); break; } anti_flickering = true; if (strlen(seq_file_name)) { seqFile = fopen (seq_file_name, "rb"); if (seqFile == NULL) { DEBUG_PRINT_ERROR("Error - Seq file %s could NOT be opened\n", seq_file_name); return -1; } else { DEBUG_PRINT("Seq file %s is opened \n", seq_file_name); seq_enabled = 1; anti_flickering = false; } } pthread_mutex_lock(&eos_lock); while (bOutputEosReached == false && cmd_error == 0) { if (seq_enabled) { pthread_mutex_unlock(&eos_lock); if (!get_next_command(seqFile)) cmd_error = process_current_command(curr_seq_command); else { printf("\n Error in get_next_cmd or EOF"); seq_enabled = 0; } pthread_mutex_lock(&eos_lock); } else pthread_cond_wait(&eos_cond, &eos_lock); if (currentStatus == PORT_SETTING_CHANGE_STATE) { pthread_mutex_unlock(&eos_lock); cmd_error = output_port_reconfig(); pthread_mutex_lock(&eos_lock); } } pthread_mutex_unlock(&eos_lock); // Wait till EOS is reached... if (bOutputEosReached) do_freeHandle_and_clean_up(currentStatus == ERROR_STATE); return 0; } int Init_Decoder() { DEBUG_PRINT("Inside %s \n", __FUNCTION__); OMX_ERRORTYPE omxresult; OMX_U32 total = 0; char vdecCompNames[50]; typedef OMX_U8* OMX_U8_PTR; char role[strlen("video_decoder") + 1]; strcpy(role, "video_decoder"); static OMX_CALLBACKTYPE call_back = {&EventHandler, &EmptyBufferDone, &FillBufferDone}; unsigned int i = 0; long bufCnt = 0; /* Init. the OpenMAX Core */ DEBUG_PRINT("\nInitializing OpenMAX Core....\n"); omxresult = OMX_Init(); if (OMX_ErrorNone != omxresult) { DEBUG_PRINT_ERROR("\n Failed to Init OpenMAX core"); return -1; } else { DEBUG_PRINT_ERROR("\nOpenMAX Core Init Done\n"); } /* Query for video decoders*/ OMX_GetComponentsOfRole(role, &total, 0); DEBUG_PRINT("\nTotal components of role=%s :%d", role, total); if (total) { /* Allocate memory for pointers to component name */ OMX_U8** vidCompNames = (OMX_U8**)malloc((sizeof(OMX_U8*))*total); if (vidCompNames == NULL) { DEBUG_PRINT_ERROR("\nFailed to allocate vidCompNames\n"); return -1; } for (i = 0; i < total; ++i) { vidCompNames[i] = (OMX_U8*)malloc(sizeof(OMX_U8)*OMX_MAX_STRINGNAME_SIZE); if (vidCompNames[i] == NULL) { DEBUG_PRINT_ERROR("\nFailed to allocate vidCompNames[%d]\n", i); return -1; } } OMX_GetComponentsOfRole(role, &total, vidCompNames); DEBUG_PRINT("\nComponents of Role:%s\n", role); for (i = 0; i < total; ++i) { DEBUG_PRINT("\nComponent Name [%s]\n",vidCompNames[i]); free(vidCompNames[i]); } free(vidCompNames); } else { DEBUG_PRINT_ERROR("No components found with Role:%s", role); } if (codec_format_option == CODEC_FORMAT_H264) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.avc", 27); //strlcpy(vdecCompNames, "OMX.SEC.qcom.video.decoder.avc", 31); } else if (codec_format_option == CODEC_FORMAT_MP4) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.mpeg4", 29); } else if (codec_format_option == CODEC_FORMAT_H263) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.h263", 28); } else if (codec_format_option == CODEC_FORMAT_VC1) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.vc1", 27); } else if (codec_format_option == CODEC_FORMAT_MPEG2) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.mpeg2", 29); } else if (file_type_option == FILE_TYPE_RCV) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.wmv", 27); } else if (file_type_option == FILE_TYPE_DIVX_4_5_6) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.divx", 28); } #ifdef _MSM8974_ else if (codec_format_option == CODEC_FORMAT_VP8) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.vp8", 27); } else if (codec_format_option == CODEC_FORMAT_MVC) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.mvc", 27); } #endif else if (codec_format_option == CODEC_FORMAT_HEVC) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.hevc", 28); DEBUG_PRINT_ERROR("vdecCompNames: %s\n", vdecCompNames); } else if (codec_format_option == CODEC_FORMAT_HEVC_HYBRID) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.hevchybrid", 34); DEBUG_PRINT_ERROR("vdecCompNames: %s\n", vdecCompNames); } #ifdef MAX_RES_1080P else if (file_type_option == FILE_TYPE_DIVX_311) { strlcpy(vdecCompNames, "OMX.qcom.video.decoder.divx311", 31); } #endif else { DEBUG_PRINT_ERROR("Error: Unsupported codec %d\n", codec_format_option); return -1; } omxresult = OMX_GetHandle((OMX_HANDLETYPE*)(&dec_handle), (OMX_STRING)vdecCompNames, NULL, &call_back); if (FAILED(omxresult)) { DEBUG_PRINT_ERROR("\nFailed to Load the component:%s\n", vdecCompNames); if (!strncmp(vdecCompNames, "OMX.qcom.video.decoder.mvc", 27)) { char platform_name[PROPERTY_VALUE_MAX] = {0}; property_get("ro.product.name", platform_name, "Name not available"); printf("Error: MVC not listed as supported codec in this platform: %s\n", platform_name); } return -1; } else { DEBUG_PRINT("\nComponent %s is in LOADED state\n", vdecCompNames); } QOMX_VIDEO_QUERY_DECODER_INSTANCES decoder_instances; omxresult = OMX_GetConfig(dec_handle, (OMX_INDEXTYPE)OMX_QcomIndexQueryNumberOfVideoDecInstance, &decoder_instances); DEBUG_PRINT("\n Number of decoder instances %d", decoder_instances.nNumOfInstances); /* Get the port information */ CONFIG_VERSION_SIZE(portParam); omxresult = OMX_GetParameter(dec_handle, OMX_IndexParamVideoInit, (OMX_PTR)&portParam); if (FAILED(omxresult)) { DEBUG_PRINT_ERROR("ERROR - Failed to get Port Param\n"); return -1; } else { DEBUG_PRINT("portParam.nPorts:%d\n", portParam.nPorts); DEBUG_PRINT("portParam.nStartPortNumber:%d\n", portParam.nStartPortNumber); } /* Set the compression format on i/p port */ if (codec_format_option == CODEC_FORMAT_H264) { portFmt.format.video.eCompressionFormat = OMX_VIDEO_CodingAVC; } else if (codec_format_option == CODEC_FORMAT_MVC) { portFmt.format.video.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingMVC; } else if (codec_format_option == CODEC_FORMAT_MP4) { portFmt.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG4; } else if (codec_format_option == CODEC_FORMAT_H263) { portFmt.format.video.eCompressionFormat = OMX_VIDEO_CodingH263; } else if (codec_format_option == CODEC_FORMAT_VC1) { portFmt.format.video.eCompressionFormat = OMX_VIDEO_CodingWMV; } else if (codec_format_option == CODEC_FORMAT_DIVX) { portFmt.format.video.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingDivx; } else if (codec_format_option == CODEC_FORMAT_MPEG2) { portFmt.format.video.eCompressionFormat = OMX_VIDEO_CodingMPEG2; } else if (codec_format_option == CODEC_FORMAT_HEVC || codec_format_option == CODEC_FORMAT_HEVC_HYBRID) { portFmt.format.video.eCompressionFormat = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; } else { DEBUG_PRINT_ERROR("Error: Unsupported codec %d\n", codec_format_option); } if (thumbnailMode == 1) { QOMX_ENABLETYPE thumbNailMode; thumbNailMode.bEnable = OMX_TRUE; OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamVideoSyncFrameDecodingMode, (OMX_PTR)&thumbNailMode); DEBUG_PRINT("Enabled Thumbnail mode\n"); } return 0; } int Play_Decoder() { OMX_VIDEO_PARAM_PORTFORMATTYPE videoportFmt; memset(&videoportFmt, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE)); int i, bufCnt, index = 0; int frameSize=0; OMX_ERRORTYPE ret = OMX_ErrorNone; OMX_BUFFERHEADERTYPE* pBuffer = NULL; DEBUG_PRINT("Inside %s \n", __FUNCTION__); /* open the i/p and o/p files based on the video file format passed */ if (open_video_file()) { DEBUG_PRINT_ERROR("Error in opening video file\n"); return -1; } OMX_QCOM_PARAM_PORTDEFINITIONTYPE inputPortFmt; memset(&inputPortFmt, 0, sizeof(OMX_QCOM_PARAM_PORTDEFINITIONTYPE)); CONFIG_VERSION_SIZE(inputPortFmt); inputPortFmt.nPortIndex = 0; // input port switch (file_type_option) { case FILE_TYPE_DAT_PER_AU: case FILE_TYPE_PICTURE_START_CODE: case FILE_TYPE_MPEG2_START_CODE: case FILE_TYPE_264_START_CODE_BASED: case FILE_TYPE_RCV: case FILE_TYPE_VC1: #ifdef MAX_RES_1080P case FILE_TYPE_DIVX_311: #endif { inputPortFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame; break; } case FILE_TYPE_ARBITRARY_BYTES: case FILE_TYPE_264_NAL_SIZE_LENGTH: case FILE_TYPE_DIVX_4_5_6: { inputPortFmt.nFramePackingFormat = OMX_QCOM_FramePacking_Arbitrary; break; } #ifdef _MSM8974_ case FILE_TYPE_VP8: { inputPortFmt.nFramePackingFormat = OMX_QCOM_FramePacking_OnlyOneCompleteFrame; break; } #endif default: inputPortFmt.nFramePackingFormat = OMX_QCOM_FramePacking_Unspecified; } OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexPortDefn, (OMX_PTR)&inputPortFmt); #ifdef USE_EXTERN_PMEM_BUF OMX_QCOM_PARAM_PORTDEFINITIONTYPE outPortFmt; memset(&outPortFmt, 0, sizeof(OMX_QCOM_PARAM_PORTDEFINITIONTYPE)); CONFIG_VERSION_SIZE(outPortFmt); outPortFmt.nPortIndex = 1; // output port outPortFmt.nCacheAttr = OMX_QCOM_CacheAttrNone; outPortFmt.nMemRegion = OMX_QCOM_MemRegionSMI; OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexPortDefn, (OMX_PTR)&outPortFmt); OMX_QCOM_PLATFORMPRIVATE_EXTN outPltPvtExtn; memset(&outPltPvtExtn, 0, sizeof(OMX_QCOM_PLATFORMPRIVATE_EXTN)); CONFIG_VERSION_SIZE(outPltPvtExtn); outPltPvtExtn.nPortIndex = 1; // output port outPltPvtExtn.type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexPlatformPvt, (OMX_PTR)&outPltPvtExtn); use_external_pmem_buf = OMX_TRUE; #endif QOMX_ENABLETYPE extra_data; extra_data.bEnable = OMX_TRUE; char frameinfo_value[PROPERTY_VALUE_MAX] = {0}; char interlace_value[PROPERTY_VALUE_MAX] = {0}; char h264info_value[PROPERTY_VALUE_MAX] = {0}; char video_qp_value[PROPERTY_VALUE_MAX] = {0}; char videoinput_bitsinfo_value[PROPERTY_VALUE_MAX] = {0}; OMX_U32 frameinfo = 0,interlace = 0,h264info =0, video_qp =0, videoinput_bitsinfo =0; property_get("vidc.vdec.debug.frameinfo", frameinfo_value, "0"); frameinfo = atoi(frameinfo_value); if (frameinfo) { OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamFrameInfoExtraData, (OMX_PTR)&extra_data); } property_get("vidc.vdec.debug.interlace", interlace_value, "0"); interlace = atoi(interlace_value); if (interlace) { OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamInterlaceExtraData, (OMX_PTR)&extra_data); } property_get("vidc.vdec.debug.h264info", h264info_value, "0"); h264info = atoi(h264info_value); if (h264info) { OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamH264TimeInfo, (OMX_PTR)&extra_data); } property_get("vidc.vdec.debug.video_qp_value", video_qp_value, "0"); video_qp = atoi(video_qp_value); if (video_qp) { OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamVideoQPExtraData, (OMX_PTR)&extra_data); } property_get("vidc.vdec.debug.input_bitsinfo", videoinput_bitsinfo_value, "0"); videoinput_bitsinfo = atoi(videoinput_bitsinfo_value); if (videoinput_bitsinfo) { OMX_SetParameter(dec_handle,(OMX_INDEXTYPE)OMX_QcomIndexParamVideoInputBitsInfoExtraData, (OMX_PTR)&extra_data); } /* Query the decoder outport's min buf requirements */ CONFIG_VERSION_SIZE(portFmt); /* Port for which the Client needs to obtain info */ portFmt.nPortIndex = portParam.nStartPortNumber; OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); DEBUG_PRINT("\nDec: Min Buffer Count %d\n", portFmt.nBufferCountMin); DEBUG_PRINT("\nDec: Buffer Size %d\n", portFmt.nBufferSize); if (OMX_DirInput != portFmt.eDir) { printf ("\nDec: Expect Input Port\n"); return -1; } #ifdef MAX_RES_1080P if ( (codec_format_option == CODEC_FORMAT_DIVX) && (file_type_option == FILE_TYPE_DIVX_311) ) { int off; if ( read(inputBufferFileFd, &width, 4 ) == -1 ) { DEBUG_PRINT_ERROR("\nFailed to read width for divx\n"); return -1; } DEBUG_PRINT("\nWidth for DIVX = %d\n", width); if ( read(inputBufferFileFd, &height, 4 ) == -1 ) { DEBUG_PRINT_ERROR("\nFailed to read height for divx\n"); return -1; } DEBUG_PRINT("\nHeight for DIVX = %u\n", height); sliceheight = height; stride = width; } #endif #ifdef _MSM8974_ if ( (codec_format_option == CODEC_FORMAT_VC1) && (file_type_option == FILE_TYPE_RCV) ) { //parse struct_A data to get height and width information unsigned int temp; lseek64(inputBufferFileFd, 0, SEEK_SET); if (read(inputBufferFileFd, &temp, 4) < 0) { DEBUG_PRINT_ERROR("\nFailed to read vc1 data\n"); return -1; } //Refer to Annex L of SMPTE 421M-2006 VC1 decoding standard //We need to skip 12 bytes after 0xC5 in sequence layer data //structure to read struct_A, which includes height and //width information. if ((temp & 0xFF000000) == 0xC5000000) { lseek64(inputBufferFileFd, 12, SEEK_SET); if ( read(inputBufferFileFd, &height, 4 ) < -1 ) { DEBUG_PRINT_ERROR("\nFailed to read height for vc-1\n"); return -1; } if ( read(inputBufferFileFd, &width, 4 ) == -1 ) { DEBUG_PRINT_ERROR("\nFailed to read width for vc-1\n"); return -1; } lseek64(inputBufferFileFd, 0, SEEK_SET); } if ((temp & 0xFF000000) == 0x85000000) { lseek64(inputBufferFileFd, 0, SEEK_SET); } DEBUG_PRINT("\n RCV clip width = %u height = %u \n",width, height); } #endif crop_rect.nWidth = width; crop_rect.nHeight = height; bufCnt = 0; portFmt.format.video.nFrameHeight = height; portFmt.format.video.nFrameWidth = width; portFmt.format.video.xFramerate = fps; OMX_SetParameter(dec_handle,OMX_IndexParamPortDefinition, (OMX_PTR)&portFmt); OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition, &portFmt); DEBUG_PRINT("\nDec: New Min Buffer Count %d", portFmt.nBufferCountMin); CONFIG_VERSION_SIZE(videoportFmt); #ifdef MAX_RES_720P if (color_fmt_type == 0) { color_fmt = OMX_COLOR_FormatYUV420SemiPlanar; } else { color_fmt = (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka; } #elif _MSM8974_ if (codec_format_option == CODEC_FORMAT_MVC) color_fmt = (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32mMultiView; else color_fmt = (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m; #else color_fmt = (OMX_COLOR_FORMATTYPE) QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka; #endif while (ret == OMX_ErrorNone) { videoportFmt.nPortIndex = 1; videoportFmt.nIndex = index; ret = OMX_GetParameter(dec_handle, OMX_IndexParamVideoPortFormat, (OMX_PTR)&videoportFmt); if ((ret == OMX_ErrorNone) && (videoportFmt.eColorFormat == color_fmt)) { DEBUG_PRINT("\n Format[%u] supported by OMX Decoder", color_fmt); break; } index++; } if (ret == OMX_ErrorNone) { if (OMX_SetParameter(dec_handle, OMX_IndexParamVideoPortFormat, (OMX_PTR)&videoportFmt) != OMX_ErrorNone) { DEBUG_PRINT_ERROR("\n Setting Tile format failed"); return -1; } } else { DEBUG_PRINT_ERROR("\n Error in retrieving supported color formats"); return -1; } picture_order.nPortIndex = 1; DEBUG_PRINT("\nSet picture order\n"); if (OMX_SetParameter(dec_handle, (OMX_INDEXTYPE)OMX_QcomIndexParamVideoDecoderPictureOrder, (OMX_PTR)&picture_order) != OMX_ErrorNone) { printf("\n ERROR: Setting picture order!"); return -1; } DEBUG_PRINT("\nVideo format: W x H (%d x %d)", portFmt.format.video.nFrameWidth, portFmt.format.video.nFrameHeight); if (codec_format_option == CODEC_FORMAT_H264 || codec_format_option == CODEC_FORMAT_HEVC || codec_format_option == CODEC_FORMAT_HEVC_HYBRID) { OMX_VIDEO_CONFIG_NALSIZE naluSize; naluSize.nNaluBytes = nalSize; DEBUG_PRINT("\n Nal length is %d index %d",nalSize,OMX_IndexConfigVideoNalSize); OMX_SetConfig(dec_handle,OMX_IndexConfigVideoNalSize,(OMX_PTR)&naluSize); DEBUG_PRINT("SETTING THE NAL SIZE to %d\n",naluSize.nNaluBytes); } DEBUG_PRINT("\nOMX_SendCommand Decoder -> IDLE\n"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StateIdle,0); input_buf_cnt = portFmt.nBufferCountActual; DEBUG_PRINT("Transition to Idle State succesful...\n"); #if ALLOCATE_BUFFER // Allocate buffer on decoder's i/p port error = Allocate_Buffer(dec_handle, &pInputBufHdrs, portFmt.nPortIndex, portFmt.nBufferCountActual, portFmt.nBufferSize); if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("Error - OMX_AllocateBuffer Input buffer error\n"); return -1; } else { DEBUG_PRINT("\nOMX_AllocateBuffer Input buffer success\n"); } #else // Use buffer on decoder's i/p port input_use_buffer = true; DEBUG_PRINT_ERROR("\n before OMX_UseBuffer %p", &pInputBufHdrs); error = use_input_buffer(dec_handle, &pInputBufHdrs, portFmt.nPortIndex, portFmt.nBufferSize, portFmt.nBufferCountActual); if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("ERROR - OMX_UseBuffer Input buffer failed"); return -1; } else { DEBUG_PRINT("OMX_UseBuffer Input buffer success\n"); } #endif portFmt.nPortIndex = portParam.nStartPortNumber+1; // Port for which the Client needs to obtain info OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); DEBUG_PRINT("nMin Buffer Count=%d", portFmt.nBufferCountMin); DEBUG_PRINT("nBuffer Size=%d", portFmt.nBufferSize); if (OMX_DirOutput != portFmt.eDir) { DEBUG_PRINT_ERROR("Error - Expect Output Port\n"); return -1; } if (anti_flickering) { ret = OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); if (ret != OMX_ErrorNone) { DEBUG_PRINT_ERROR("%s: OMX_GetParameter failed: %d",__FUNCTION__, ret); return -1; } portFmt.nBufferCountActual += 1; ret = OMX_SetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); if (ret != OMX_ErrorNone) { DEBUG_PRINT_ERROR("%s: OMX_SetParameter failed: %d",__FUNCTION__, ret); return -1; } } #ifndef USE_EGL_IMAGE_TEST_APP if (use_external_pmem_buf) { DEBUG_PRINT_ERROR("\n Use External pmem buf: OMX_UseBuffer %p", &pInputBufHdrs); error = use_output_buffer_multiple_fd(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferSize, portFmt.nBufferCountActual); } else { /* Allocate buffer on decoder's o/p port */ error = Allocate_Buffer(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferCountActual, portFmt.nBufferSize); } free_op_buf_cnt = portFmt.nBufferCountActual; if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("Error - OMX_AllocateBuffer Output buffer error\n"); return -1; } else { DEBUG_PRINT("OMX_AllocateBuffer Output buffer success\n"); } #else DEBUG_PRINT_ERROR("\n before OMX_UseBuffer %p", &pInputBufHdrs); error = use_output_buffer(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferSize, portFmt.nBufferCountActual); free_op_buf_cnt = portFmt.nBufferCountActual; if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("ERROR - OMX_UseBuffer Input buffer failed"); return -1; } else { DEBUG_PRINT("OMX_UseBuffer Input buffer success\n"); } #endif wait_for_event(); if (currentStatus == ERROR_STATE) { do_freeHandle_and_clean_up(true); return -1; } if (freeHandle_option == FREE_HANDLE_AT_IDLE) { OMX_STATETYPE state = OMX_StateInvalid; OMX_GetState(dec_handle, &state); if (state == OMX_StateIdle) { DEBUG_PRINT("Decoder is in OMX_StateIdle and trying to call OMX_FreeHandle \n"); do_freeHandle_and_clean_up(false); } else { DEBUG_PRINT_ERROR("Error - Decoder is in state %d and trying to call OMX_FreeHandle \n", state); do_freeHandle_and_clean_up(true); } return -1; } DEBUG_PRINT("OMX_SendCommand Decoder -> Executing\n"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StateExecuting,0); wait_for_event(); if (currentStatus == ERROR_STATE) { do_freeHandle_and_clean_up(true); return -1; } if (pOutYUVBufHdrs == NULL) { DEBUG_PRINT_ERROR("Error - pOutYUVBufHdrs is NULL\n"); return -1; } for (bufCnt=0; bufCnt < (int)portFmt.nBufferCountActual; ++bufCnt) { DEBUG_PRINT("OMX_FillThisBuffer on output buf no.%d\n",bufCnt); if (pOutYUVBufHdrs[bufCnt] == NULL) { DEBUG_PRINT_ERROR("Error - pOutYUVBufHdrs[%d] is NULL\n", bufCnt); return -1; } pOutYUVBufHdrs[bufCnt]->nOutputPortIndex = 1; pOutYUVBufHdrs[bufCnt]->nFlags &= ~OMX_BUFFERFLAG_EOS; ret = OMX_FillThisBuffer(dec_handle, pOutYUVBufHdrs[bufCnt]); if (OMX_ErrorNone != ret) DEBUG_PRINT_ERROR("Error - OMX_FillThisBuffer failed with result %d\n", ret); else { DEBUG_PRINT("OMX_FillThisBuffer success!\n"); free_op_buf_cnt--; } } used_ip_buf_cnt = input_buf_cnt; rcv_v1 = 0; //QPERF_START(client_decode); if (codec_format_option == CODEC_FORMAT_VC1) { pInputBufHdrs[0]->nOffset = 0; if (file_type_option == FILE_TYPE_RCV) { frameSize = Read_Buffer_From_RCV_File_Seq_Layer(pInputBufHdrs[0]); pInputBufHdrs[0]->nFilledLen = frameSize; DEBUG_PRINT("After Read_Buffer_From_RCV_File_Seq_Layer, " "frameSize %d\n", frameSize); } else if (file_type_option == FILE_TYPE_VC1) { bHdrflag = 1; pInputBufHdrs[0]->nFilledLen = Read_Buffer(pInputBufHdrs[0]); bHdrflag = 0; DEBUG_PRINT_ERROR("After 1st Read_Buffer for VC1, " "pInputBufHdrs[0]->nFilledLen %u\n", (unsigned int)pInputBufHdrs[0]->nFilledLen); } else { pInputBufHdrs[0]->nFilledLen = Read_Buffer(pInputBufHdrs[0]); DEBUG_PRINT("After Read_Buffer pInputBufHdrs[0]->nFilledLen %d\n", pInputBufHdrs[0]->nFilledLen); } pInputBufHdrs[0]->nInputPortIndex = 0; pInputBufHdrs[0]->nOffset = 0; #ifndef _MSM8974_ pInputBufHdrs[0]->nFlags = 0; #endif ret = OMX_EmptyThisBuffer(dec_handle, pInputBufHdrs[0]); if (ret != OMX_ErrorNone) { DEBUG_PRINT_ERROR("ERROR - OMX_EmptyThisBuffer failed with result %d\n", ret); do_freeHandle_and_clean_up(true); return -1; } else { etb_count++; DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); } i = 1; #ifdef _MSM8974_ pInputBufHdrs[0]->nFlags = 0; #endif } else { i = 0; } for (i; i < used_ip_buf_cnt; i++) { pInputBufHdrs[i]->nInputPortIndex = 0; pInputBufHdrs[i]->nOffset = 0; if ((frameSize = Read_Buffer(pInputBufHdrs[i])) <= 0 ) { DEBUG_PRINT("NO FRAME READ\n"); pInputBufHdrs[i]->nFilledLen = frameSize; pInputBufHdrs[i]->nInputPortIndex = 0; pInputBufHdrs[i]->nFlags |= OMX_BUFFERFLAG_EOS;; bInputEosReached = true; OMX_EmptyThisBuffer(dec_handle, pInputBufHdrs[i]); etb_count++; DEBUG_PRINT("File is small::Either EOS or Some Error while reading file\n"); break; } pInputBufHdrs[i]->nFilledLen = frameSize; pInputBufHdrs[i]->nInputPortIndex = 0; pInputBufHdrs[i]->nFlags = 0; //pBufHdr[bufCnt]->pAppPrivate = this; DEBUG_PRINT("%s: Timestamp sent(%lld)", __FUNCTION__, pInputBufHdrs[i]->nTimeStamp); ret = OMX_EmptyThisBuffer(dec_handle, pInputBufHdrs[i]); if (OMX_ErrorNone != ret) { DEBUG_PRINT_ERROR("ERROR - OMX_EmptyThisBuffer failed with result %d\n", ret); do_freeHandle_and_clean_up(true); return -1; } else { DEBUG_PRINT("OMX_EmptyThisBuffer success!\n"); etb_count++; } } if (0 != pthread_create(&ebd_thread_id, NULL, ebd_thread, NULL)) { printf("\n Error in Creating fbd_thread \n"); free_queue(etb_queue); free_queue(fbd_queue); return -1; } // wait for event port settings changed event DEBUG_PRINT("wait_for_event: dyn reconfig"); wait_for_event(); DEBUG_PRINT("wait_for_event: dyn reconfig rcvd, currentStatus %d\n", currentStatus); if (currentStatus == ERROR_STATE) { printf("Error - ERROR_STATE\n"); do_freeHandle_and_clean_up(true); return -1; } else if (currentStatus == PORT_SETTING_CHANGE_STATE) { if (output_port_reconfig() != 0) { DEBUG_PRINT("output_port_reconfig - ERROR_STATE\n"); do_freeHandle_and_clean_up(true); return -1; } } if (freeHandle_option == FREE_HANDLE_AT_EXECUTING) { OMX_STATETYPE state = OMX_StateInvalid; OMX_GetState(dec_handle, &state); if (state == OMX_StateExecuting) { DEBUG_PRINT("Decoder is in OMX_StateExecuting and trying to call OMX_FreeHandle \n"); do_freeHandle_and_clean_up(false); } else { DEBUG_PRINT_ERROR("Error - Decoder is in state %d and trying to call OMX_FreeHandle \n", state); do_freeHandle_and_clean_up(true); } return -1; } else if (freeHandle_option == FREE_HANDLE_AT_PAUSE) { OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StatePause,0); wait_for_event(); OMX_STATETYPE state = OMX_StateInvalid; OMX_GetState(dec_handle, &state); if (state == OMX_StatePause) { DEBUG_PRINT("Decoder is in OMX_StatePause and trying to call OMX_FreeHandle \n"); do_freeHandle_and_clean_up(false); } else { DEBUG_PRINT_ERROR("Error - Decoder is in state %d and trying to call OMX_FreeHandle \n", state); do_freeHandle_and_clean_up(true); } return -1; } return 0; } static OMX_ERRORTYPE Allocate_Buffer ( OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***pBufHdrs, OMX_U32 nPortIndex, long bufCntMin, long bufSize) { DEBUG_PRINT("Inside %s \n", __FUNCTION__); OMX_ERRORTYPE error=OMX_ErrorNone; long bufCnt=0; if (currentStatus == ERROR_STATE) { return OMX_ErrorInvalidState; } DEBUG_PRINT("pBufHdrs = %x,bufCntMin = %d\n", pBufHdrs, bufCntMin); *pBufHdrs= (OMX_BUFFERHEADERTYPE **) malloc(sizeof(OMX_BUFFERHEADERTYPE)*bufCntMin); for (bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { DEBUG_PRINT("OMX_AllocateBuffer No %d \n", bufCnt); error = OMX_AllocateBuffer(dec_handle, &((*pBufHdrs)[bufCnt]), nPortIndex, NULL, bufSize); } return error; } static OMX_ERRORTYPE use_input_buffer ( OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***pBufHdrs, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufCntMin) { DEBUG_PRINT("Inside %s \n", __FUNCTION__); OMX_ERRORTYPE error=OMX_ErrorNone; long bufCnt=0; OMX_U8* pvirt = NULL; *pBufHdrs= (OMX_BUFFERHEADERTYPE **) malloc(sizeof(OMX_BUFFERHEADERTYPE)* bufCntMin); if (*pBufHdrs == NULL) { DEBUG_PRINT_ERROR("\n m_inp_heap_ptr Allocation failed "); return OMX_ErrorInsufficientResources; } for (bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { // allocate input buffers DEBUG_PRINT("OMX_UseBuffer No %d %d \n", bufCnt, bufSize); pvirt = (OMX_U8*) malloc (bufSize); if (pvirt == NULL) { DEBUG_PRINT_ERROR("\n pvirt Allocation failed "); return OMX_ErrorInsufficientResources; } error = OMX_UseBuffer(dec_handle, &((*pBufHdrs)[bufCnt]), nPortIndex, NULL, bufSize, pvirt); } return error; } static OMX_ERRORTYPE use_output_buffer ( OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***pBufHdrs, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufCntMin) { DEBUG_PRINT("Inside %s \n", __FUNCTION__); OMX_ERRORTYPE error=OMX_ErrorNone; long bufCnt=0; OMX_U8* pvirt = NULL; *pBufHdrs= (OMX_BUFFERHEADERTYPE **) malloc(sizeof(OMX_BUFFERHEADERTYPE)* bufCntMin); if (*pBufHdrs == NULL) { DEBUG_PRINT_ERROR("\n m_inp_heap_ptr Allocation failed "); return OMX_ErrorInsufficientResources; } output_use_buffer = true; p_eglHeaders = (struct temp_egl **) malloc(sizeof(struct temp_egl *)* bufCntMin); if (!p_eglHeaders) { DEBUG_PRINT_ERROR("\n EGL allocation failed"); return OMX_ErrorInsufficientResources; } for (bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { // allocate input buffers DEBUG_PRINT("OMX_UseBuffer No %d %d \n", bufCnt, bufSize); p_eglHeaders[bufCnt] = (struct temp_egl*) malloc(sizeof(struct temp_egl)); if (!p_eglHeaders[bufCnt]) { DEBUG_PRINT_ERROR("\n EGL allocation failed"); return OMX_ErrorInsufficientResources; } p_eglHeaders[bufCnt]->pmem_fd = open(PMEM_DEVICE,O_RDWR); p_eglHeaders[bufCnt]->offset = 0; if (p_eglHeaders[bufCnt]->pmem_fd < 0) { DEBUG_PRINT_ERROR("\n open failed %s",PMEM_DEVICE); return OMX_ErrorInsufficientResources; } #ifndef USE_ION /* TBD - this commenting is dangerous */ align_pmem_buffers(p_eglHeaders[bufCnt]->pmem_fd, bufSize, 8192); #endif DEBUG_PRINT_ERROR("\n allocation size %u pmem fd %d",(unsigned int)bufSize,p_eglHeaders[bufCnt]->pmem_fd); pvirt = (unsigned char *)mmap(NULL,bufSize,PROT_READ|PROT_WRITE, MAP_SHARED,p_eglHeaders[bufCnt]->pmem_fd,0); DEBUG_PRINT_ERROR("\n Virtaul Address %p Size %u",pvirt,(unsigned int)bufSize); if (pvirt == MAP_FAILED) { DEBUG_PRINT_ERROR("\n mmap failed for buffers"); return OMX_ErrorInsufficientResources; } use_buf_virt_addr[bufCnt] = (unsigned)pvirt; error = OMX_UseEGLImage(dec_handle, &((*pBufHdrs)[bufCnt]), nPortIndex, pvirt,(void *)p_eglHeaders[bufCnt]); } return error; } static OMX_ERRORTYPE use_output_buffer_multiple_fd ( OMX_COMPONENTTYPE *dec_handle, OMX_BUFFERHEADERTYPE ***pBufHdrs, OMX_U32 nPortIndex, OMX_U32 bufSize, long bufCntMin) { DEBUG_PRINT("Inside %s \n", __FUNCTION__); OMX_ERRORTYPE error=OMX_ErrorNone; long bufCnt=0; OMX_U8* pvirt = NULL; *pBufHdrs= (OMX_BUFFERHEADERTYPE **) malloc(sizeof(OMX_BUFFERHEADERTYPE)* bufCntMin); if (*pBufHdrs == NULL) { DEBUG_PRINT_ERROR("\n m_inp_heap_ptr Allocation failed "); return OMX_ErrorInsufficientResources; } pPlatformList = (OMX_QCOM_PLATFORM_PRIVATE_LIST *) malloc(sizeof(OMX_QCOM_PLATFORM_PRIVATE_LIST)* bufCntMin); if (pPlatformList == NULL) { DEBUG_PRINT_ERROR("\n pPlatformList Allocation failed "); return OMX_ErrorInsufficientResources; } pPlatformEntry = (OMX_QCOM_PLATFORM_PRIVATE_ENTRY *) malloc(sizeof(OMX_QCOM_PLATFORM_PRIVATE_ENTRY)* bufCntMin); if (pPlatformEntry == NULL) { DEBUG_PRINT_ERROR("\n pPlatformEntry Allocation failed "); return OMX_ErrorInsufficientResources; } pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) malloc(sizeof(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO)* bufCntMin); if (pPMEMInfo == NULL) { DEBUG_PRINT_ERROR("\n pPMEMInfo Allocation failed "); return OMX_ErrorInsufficientResources; } //output_use_buffer = true; for (bufCnt=0; bufCnt < bufCntMin; ++bufCnt) { // allocate input buffers DEBUG_PRINT("OMX_UseBuffer_multiple_fd No %d %d \n", bufCnt, bufSize); pPlatformEntry[bufCnt].type = OMX_QCOM_PLATFORM_PRIVATE_PMEM; pPlatformEntry[bufCnt].entry = &pPMEMInfo[bufCnt]; // Initialize the Platform List pPlatformList[bufCnt].nEntries = 1; pPlatformList[bufCnt].entryList = &pPlatformEntry[bufCnt]; pPMEMInfo[bufCnt].offset = 0; pPMEMInfo[bufCnt].pmem_fd = open(PMEM_DEVICE,O_RDWR);; if ((int)pPMEMInfo[bufCnt].pmem_fd < 0) { DEBUG_PRINT_ERROR("\n open failed %s",PMEM_DEVICE); return OMX_ErrorInsufficientResources; } #ifndef USE_ION /* TBD - this commenting is dangerous */ align_pmem_buffers(pPMEMInfo[bufCnt].pmem_fd, bufSize, 8192); #endif DEBUG_PRINT("\n allocation size %d pmem fd 0x%x",bufSize,pPMEMInfo[bufCnt].pmem_fd); pvirt = (unsigned char *)mmap(NULL,bufSize,PROT_READ|PROT_WRITE, MAP_SHARED,pPMEMInfo[bufCnt].pmem_fd,0); getFreePmem(); DEBUG_PRINT("\n Virtaul Address %p Size %d pmem_fd=0x%x",pvirt,bufSize,pPMEMInfo[bufCnt].pmem_fd); if (pvirt == MAP_FAILED) { DEBUG_PRINT_ERROR("\n mmap failed for buffers"); return OMX_ErrorInsufficientResources; } use_buf_virt_addr[bufCnt] = (unsigned)pvirt; error = OMX_UseBuffer(dec_handle, &((*pBufHdrs)[bufCnt]), nPortIndex, &pPlatformList[bufCnt], bufSize, pvirt); } return error; } static void do_freeHandle_and_clean_up(bool isDueToError) { int bufCnt = 0; OMX_STATETYPE state = OMX_StateInvalid; OMX_GetState(dec_handle, &state); if (state == OMX_StateExecuting || state == OMX_StatePause) { DEBUG_PRINT("Requesting transition to Idle"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StateIdle, 0); do { wait_for_event(); OMX_GetState(dec_handle, &state); DEBUG_PRINT("returned state %d", state); } while ((state != OMX_StateIdle) && (state != OMX_StateInvalid)); } OMX_GetState(dec_handle, &state); if (state == OMX_StateIdle) { DEBUG_PRINT("Requesting transition to Loaded"); OMX_SendCommand(dec_handle, OMX_CommandStateSet, OMX_StateLoaded, 0); for (bufCnt=0; bufCnt < input_buf_cnt; ++bufCnt) { if (pInputBufHdrs[bufCnt]->pBuffer && input_use_buffer) { free(pInputBufHdrs[bufCnt]->pBuffer); pInputBufHdrs[bufCnt]->pBuffer = NULL; DEBUG_PRINT_ERROR("\nFree(pInputBufHdrs[%d]->pBuffer)",bufCnt); } OMX_FreeBuffer(dec_handle, 0, pInputBufHdrs[bufCnt]); } if (pInputBufHdrs) { free(pInputBufHdrs); pInputBufHdrs = NULL; } for (bufCnt = 0; bufCnt < (int)portFmt.nBufferCountActual; ++bufCnt) { if (output_use_buffer && p_eglHeaders) { if (p_eglHeaders[bufCnt]) { munmap (pOutYUVBufHdrs[bufCnt]->pBuffer, pOutYUVBufHdrs[bufCnt]->nAllocLen); close(p_eglHeaders[bufCnt]->pmem_fd); p_eglHeaders[bufCnt]->pmem_fd = -1; free(p_eglHeaders[bufCnt]); p_eglHeaders[bufCnt] = NULL; } } if (use_external_pmem_buf) { DEBUG_PRINT("Freeing in external pmem case: buffer=0x%x, pmem_fd=0x%d", pOutYUVBufHdrs[bufCnt]->pBuffer, pPMEMInfo[bufCnt].pmem_fd); if (pOutYUVBufHdrs[bufCnt]->pBuffer) { munmap (pOutYUVBufHdrs[bufCnt]->pBuffer, pOutYUVBufHdrs[bufCnt]->nAllocLen); } if (&pPMEMInfo[bufCnt]) { close(pPMEMInfo[bufCnt].pmem_fd); pPMEMInfo[bufCnt].pmem_fd = -1; } } OMX_FreeBuffer(dec_handle, 1, pOutYUVBufHdrs[bufCnt]); } if (p_eglHeaders) { free(p_eglHeaders); p_eglHeaders = NULL; } if (pPMEMInfo) { DEBUG_PRINT("Freeing in external pmem case:PMEM"); free(pPMEMInfo); pPMEMInfo = NULL; } if (pPlatformEntry) { DEBUG_PRINT("Freeing in external pmem case:ENTRY"); free(pPlatformEntry); pPlatformEntry = NULL; } if (pPlatformList) { DEBUG_PRINT("Freeing in external pmem case:LIST"); free(pPlatformList); pPlatformList = NULL; } wait_for_event(); } DEBUG_PRINT("[OMX Vdec Test] - Free handle decoder\n"); OMX_ERRORTYPE result = OMX_FreeHandle(dec_handle); if (result != OMX_ErrorNone) { DEBUG_PRINT_ERROR("[OMX Vdec Test] - OMX_FreeHandle error. Error code: %d\n", result); } dec_handle = NULL; /* Deinit OpenMAX */ DEBUG_PRINT("[OMX Vdec Test] - De-initializing OMX \n"); OMX_Deinit(); DEBUG_PRINT("[OMX Vdec Test] - closing all files\n"); if (inputBufferFileFd != -1) { close(inputBufferFileFd); inputBufferFileFd = -1; } DEBUG_PRINT("[OMX Vdec Test] - after free inputfile\n"); if (takeYuvLog && outputBufferFile) { fclose(outputBufferFile); outputBufferFile = NULL; } #ifdef _MSM8974_ if (crcFile) { fclose(crcFile); crcFile = NULL; } #endif DEBUG_PRINT("[OMX Vdec Test] - after free outputfile\n"); if (etb_queue) { free_queue(etb_queue); etb_queue = NULL; } DEBUG_PRINT("[OMX Vdec Test] - after free etb_queue \n"); if (fbd_queue) { free_queue(fbd_queue); fbd_queue = NULL; } DEBUG_PRINT("[OMX Vdec Test] - after free iftb_queue\n"); printf("*****************************************\n"); if (isDueToError) printf("************...TEST FAILED...************\n"); else printf("**********...TEST SUCCESSFULL...*********\n"); printf("*****************************************\n"); } static int Read_Buffer_From_DAT_File(OMX_BUFFERHEADERTYPE *pBufHdr) { long frameSize=0; char temp_buffer[10]; char temp_byte; int bytes_read=0; int i=0; unsigned char *read_buffer=NULL; char c = '1'; //initialize to anything except '\0'(0) char inputFrameSize[12]; int count =0; int cnt = 0; memset(temp_buffer, 0, sizeof(temp_buffer)); DEBUG_PRINT("Inside %s \n", __FUNCTION__); while (cnt < 10) /* Check the input file format, may result in infinite loop */ { DEBUG_PRINT("loop[%d] count[%d]\n",cnt,count); count = read( inputBufferFileFd, &inputFrameSize[cnt], 1); if (inputFrameSize[cnt] == '\0' ) break; cnt++; } inputFrameSize[cnt]='\0'; frameSize = atoi(inputFrameSize); pBufHdr->nFilledLen = 0; /* get the frame length */ lseek64(inputBufferFileFd, -1, SEEK_CUR); bytes_read = read(inputBufferFileFd, pBufHdr->pBuffer, frameSize); DEBUG_PRINT("Actual frame Size [%d] bytes_read using fread[%d]\n", frameSize, bytes_read); if (bytes_read == 0 || bytes_read < frameSize ) { DEBUG_PRINT("Bytes read Zero After Read frame Size \n"); DEBUG_PRINT("Checking VideoPlayback Count:video_playback_count is:%d\n", video_playback_count); return 0; } pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; return bytes_read; } static int Read_Buffer_From_H264_Start_Code_File(OMX_BUFFERHEADERTYPE *pBufHdr) { int bytes_read = 0; int cnt = 0; unsigned int code = 0; int naluType = 0; int newFrame = 0; char *dataptr = (char *)pBufHdr->pBuffer; DEBUG_PRINT("Inside %s", __FUNCTION__); do { newFrame = 0; bytes_read = read(inputBufferFileFd, &dataptr[cnt], 1); if (!bytes_read) { DEBUG_PRINT("\n%s: Bytes read Zero", __FUNCTION__); break; } code <<= 8; code |= (0x000000FF & dataptr[cnt]); cnt++; if ((cnt == 4) && (code != H264_START_CODE)) { DEBUG_PRINT_ERROR("\n%s: ERROR: Invalid start code found 0x%x", __FUNCTION__, code); cnt = 0; break; } if ((cnt > 4) && (code == H264_START_CODE)) { DEBUG_PRINT("%s: Found H264_START_CODE", __FUNCTION__); bytes_read = read(inputBufferFileFd, &dataptr[cnt], 1); if (!bytes_read) { DEBUG_PRINT("\n%s: Bytes read Zero", __FUNCTION__); break; } DEBUG_PRINT("%s: READ Byte[%d] = 0x%x", __FUNCTION__, cnt, dataptr[cnt]); naluType = dataptr[cnt] & 0x1F; cnt++; if ((naluType == 1) || (naluType == 5)) { DEBUG_PRINT("%s: Found AU", __FUNCTION__); bytes_read = read(inputBufferFileFd, &dataptr[cnt], 1); if (!bytes_read) { DEBUG_PRINT("\n%s: Bytes read Zero", __FUNCTION__); break; } DEBUG_PRINT("%s: READ Byte[%d] = 0x%x", __FUNCTION__, cnt, dataptr[cnt]); newFrame = (dataptr[cnt] & 0x80); cnt++; if (newFrame) { lseek64(inputBufferFileFd, -6, SEEK_CUR); cnt -= 6; DEBUG_PRINT("%s: Found a NAL unit (type 0x%x) of size = %d", __FUNCTION__, (dataptr[4] & 0x1F), cnt); break; } else { DEBUG_PRINT("%s: Not a New Frame", __FUNCTION__); } } else { lseek64(inputBufferFileFd, -5, SEEK_CUR); cnt -= 5; DEBUG_PRINT("%s: Found NAL unit (type 0x%x) of size = %d", __FUNCTION__, (dataptr[4] & 0x1F), cnt); break; } } } while (1); #ifdef TEST_TS_FROM_SEI if (timeStampLfile == 0) pBufHdr->nTimeStamp = 0; else pBufHdr->nTimeStamp = LLONG_MAX; #else pBufHdr->nTimeStamp = timeStampLfile; #endif timeStampLfile += timestampInterval; return cnt; } static int Read_Buffer_ArbitraryBytes(OMX_BUFFERHEADERTYPE *pBufHdr) { int bytes_read=0; DEBUG_PRINT("Inside %s \n", __FUNCTION__); bytes_read = read(inputBufferFileFd, pBufHdr->pBuffer, NUMBER_OF_ARBITRARYBYTES_READ); if (bytes_read == 0) { DEBUG_PRINT("Bytes read Zero After Read frame Size \n"); DEBUG_PRINT("Checking VideoPlayback Count:video_playback_count is:%d\n", video_playback_count); return 0; } #ifdef TEST_TS_FROM_SEI if (timeStampLfile == 0) pBufHdr->nTimeStamp = 0; else pBufHdr->nTimeStamp = LLONG_MAX; #else pBufHdr->nTimeStamp = timeStampLfile; #endif timeStampLfile += timestampInterval; return bytes_read; } static int Read_Buffer_From_Vop_Start_Code_File(OMX_BUFFERHEADERTYPE *pBufHdr) { unsigned int readOffset = 0; int bytes_read = 0; unsigned int code = 0; pBufHdr->nFilledLen = 0; static unsigned int header_code = 0; DEBUG_PRINT("Inside %s", __FUNCTION__); do { //Start codes are always byte aligned. bytes_read = read(inputBufferFileFd, &pBufHdr->pBuffer[readOffset], 1); if (bytes_read == 0 || bytes_read == -1) { DEBUG_PRINT("Bytes read Zero \n"); break; } code <<= 8; code |= (0x000000FF & pBufHdr->pBuffer[readOffset]); //VOP start code comparision if (readOffset>3) { if (!header_code ) { if ( VOP_START_CODE == code) { header_code = VOP_START_CODE; } else if ( (0xFFFFFC00 & code) == SHORT_HEADER_START_CODE ) { header_code = SHORT_HEADER_START_CODE; } } if ((header_code == VOP_START_CODE) && (code == VOP_START_CODE)) { //Seek backwards by 4 lseek64(inputBufferFileFd, -4, SEEK_CUR); readOffset-=3; break; } else if (( header_code == SHORT_HEADER_START_CODE ) && ( SHORT_HEADER_START_CODE == (code & 0xFFFFFC00))) { //Seek backwards by 4 lseek64(inputBufferFileFd, -4, SEEK_CUR); readOffset-=3; break; } } readOffset++; } while (1); pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; return readOffset; } static int Read_Buffer_From_Mpeg2_Start_Code(OMX_BUFFERHEADERTYPE *pBufHdr) { unsigned int readOffset = 0; int bytesRead = 0; unsigned int code = 0; pBufHdr->nFilledLen = 0; static unsigned int firstParse = true; unsigned int seenFrame = false; DEBUG_PRINT("Inside %s", __FUNCTION__); /* Read one byte at a time. Construct the code every byte in order to * compare to the start codes. Keep looping until we've read in a complete * frame, which can be either just a picture start code + picture, or can * include the sequence header as well */ while (1) { bytesRead = read(inputBufferFileFd, &pBufHdr->pBuffer[readOffset], 1); /* Exit the loop if we can't read any more bytes */ if (bytesRead == 0 || bytesRead == -1) { break; } /* Construct the code one byte at a time */ code <<= 8; code |= (0x000000FF & pBufHdr->pBuffer[readOffset]); /* Can't compare the code to MPEG2 start codes until we've read the * first four bytes */ if (readOffset >= 3) { /* If this is the first time we're reading from the file, then we * need to throw away the system start code information at the * beginning. We can just look for the first sequence header. */ if (firstParse) { if (code == MPEG2_SEQ_START_CODE) { /* Seek back by 4 bytes and reset code so that we can skip * down to the common case below. */ lseek(inputBufferFileFd, -4, SEEK_CUR); code = 0; readOffset -= 3; firstParse = false; continue; } } /* If we have already parsed a frame and we see a sequence header, then * the sequence header is part of the next frame so we seek back and * break. */ if (code == MPEG2_SEQ_START_CODE) { if (seenFrame) { lseek(inputBufferFileFd, -4, SEEK_CUR); readOffset -= 3; break; } /* If we haven't seen a frame yet, then read in all the data until we * either see another frame start code or sequence header start code. */ } else if (code == MPEG2_FRAME_START_CODE) { if (!seenFrame) { seenFrame = true; } else { lseek(inputBufferFileFd, -4, SEEK_CUR); readOffset -= 3; break; } } } readOffset++; } pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; return readOffset; } static int Read_Buffer_From_Size_Nal(OMX_BUFFERHEADERTYPE *pBufHdr) { // NAL unit stream processing char temp_size[SIZE_NAL_FIELD_MAX]; int i = 0; int j = 0; unsigned int size = 0; // Need to make sure that uint32 has SIZE_NAL_FIELD_MAX (4) bytes int bytes_read = 0; // read the "size_nal_field"-byte size field bytes_read = read(inputBufferFileFd, pBufHdr->pBuffer + pBufHdr->nOffset, nalSize); if (bytes_read == 0 || bytes_read == -1) { DEBUG_PRINT("Failed to read frame or it might be EOF\n"); return 0; } for (i=0; ipBuffer[pBufHdr->nOffset + j]; } size = (unsigned int)(*((unsigned int *)(temp_size))); // now read the data bytes_read = read(inputBufferFileFd, pBufHdr->pBuffer + pBufHdr->nOffset + nalSize, size); if (bytes_read != (int)size) { DEBUG_PRINT_ERROR("Failed to read frame\n"); } pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; return bytes_read + nalSize; } static int Read_Buffer_From_RCV_File_Seq_Layer(OMX_BUFFERHEADERTYPE *pBufHdr) { unsigned int readOffset = 0, size_struct_C = 0; unsigned int startcode = 0; pBufHdr->nFilledLen = 0; #ifdef _MSM8974_ pBufHdr->nFlags |= OMX_BUFFERFLAG_CODECCONFIG; #else pBufHdr->nFlags = 0; #endif DEBUG_PRINT("Inside %s \n", __FUNCTION__); read(inputBufferFileFd, &startcode, 4); /* read size of struct C as it need not be 4 always*/ read(inputBufferFileFd, &size_struct_C, 4); #ifndef _MSM8974_ /* reseek to beginning of sequence header */ lseek64(inputBufferFileFd, -8, SEEK_CUR); #endif if ((startcode & 0xFF000000) == 0xC5000000) { DEBUG_PRINT("Read_Buffer_From_RCV_File_Seq_Layer size_struct_C: %d\n", size_struct_C); #ifdef _MSM8974_ readOffset = read(inputBufferFileFd, pBufHdr->pBuffer, size_struct_C); lseek64(inputBufferFileFd, 24, SEEK_CUR); #else readOffset = read(inputBufferFileFd, pBufHdr->pBuffer, VC1_SEQ_LAYER_SIZE_WITHOUT_STRUCTC + size_struct_C); #endif } else if ((startcode & 0xFF000000) == 0x85000000) { // .RCV V1 file rcv_v1 = 1; DEBUG_PRINT("Read_Buffer_From_RCV_File_Seq_Layer size_struct_C: %d\n", size_struct_C); #ifdef _MSM8974_ readOffset = read(inputBufferFileFd, pBufHdr->pBuffer, size_struct_C); lseek64(inputBufferFileFd, 8, SEEK_CUR); #else readOffset = read(inputBufferFileFd, pBufHdr->pBuffer, VC1_SEQ_LAYER_SIZE_V1_WITHOUT_STRUCTC + size_struct_C); #endif } else { DEBUG_PRINT_ERROR("Error: Unknown VC1 clip format %x\n", startcode); } #if 0 { int i=0; printf("Read_Buffer_From_RCV_File, length %d readOffset %d\n", readOffset, readOffset); for (i=0; i<36; i++) { printf("0x%.2x ", pBufHdr->pBuffer[i]); if (i%16 == 15) { printf("\n"); } } printf("\n"); } #endif return readOffset; } static int Read_Buffer_From_RCV_File(OMX_BUFFERHEADERTYPE *pBufHdr) { unsigned int readOffset = 0; unsigned int len = 0; unsigned int key = 0; DEBUG_PRINT("Inside %s \n", __FUNCTION__); DEBUG_PRINT("Read_Buffer_From_RCV_File - nOffset %d\n", pBufHdr->nOffset); if (rcv_v1) { /* for the case of RCV V1 format, the frame header is only of 4 bytes and has only the frame size information */ readOffset = read(inputBufferFileFd, &len, 4); DEBUG_PRINT("Read_Buffer_From_RCV_File - framesize %d %x\n", len, len); } else { /* for a regular RCV file, 3 bytes comprise the frame size and 1 byte for key*/ readOffset = read(inputBufferFileFd, &len, 3); DEBUG_PRINT("Read_Buffer_From_RCV_File - framesize %d %x\n", len, len); readOffset = read(inputBufferFileFd, &key, 1); if ( (key & 0x80) == false) { DEBUG_PRINT("Read_Buffer_From_RCV_File - Non IDR frame key %x\n", key); } } if (!rcv_v1) { /* There is timestamp field only for regular RCV format and not for RCV V1 format*/ readOffset = read(inputBufferFileFd, &pBufHdr->nTimeStamp, 4); DEBUG_PRINT("Read_Buffer_From_RCV_File - timeStamp %d\n", pBufHdr->nTimeStamp); pBufHdr->nTimeStamp *= 1000; } else { pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; } if (len > pBufHdr->nAllocLen) { DEBUG_PRINT_ERROR("Error in sufficient buffer framesize %u, allocalen %u noffset %u\n",len,(unsigned int)pBufHdr->nAllocLen, (unsigned int)pBufHdr->nOffset); readOffset = read(inputBufferFileFd, pBufHdr->pBuffer+pBufHdr->nOffset, pBufHdr->nAllocLen - pBufHdr->nOffset); loff_t off = (len - readOffset)*1LL; lseek64(inputBufferFileFd, off ,SEEK_CUR); return readOffset; } else { readOffset = read(inputBufferFileFd, pBufHdr->pBuffer+pBufHdr->nOffset, len); } if (readOffset != len) { DEBUG_PRINT("EOS reach or Reading error %d, %s \n", readOffset, strerror( errno )); return 0; } #if 0 { int i=0; printf("Read_Buffer_From_RCV_File, length %d readOffset %d\n", len, readOffset); for (i=0; i<64; i++) { printf("0x%.2x ", pBufHdr->pBuffer[i]); if (i%16 == 15) { printf("\n"); } } printf("\n"); } #endif return readOffset; } static int Read_Buffer_From_VC1_File(OMX_BUFFERHEADERTYPE *pBufHdr) { static int timeStampLfile = 0; OMX_U8 *pBuffer = pBufHdr->pBuffer + pBufHdr->nOffset; DEBUG_PRINT("Inside %s \n", __FUNCTION__); unsigned int readOffset = 0; int bytes_read = 0; unsigned int code = 0, total_bytes = 0; int startCode_cnt = 0; int bSEQflag = 0; int bEntryflag = 0; unsigned int SEQbytes = 0; int numStartcodes = 0; numStartcodes = bHdrflag?1:2; do { if (total_bytes == pBufHdr->nAllocLen) { DEBUG_PRINT_ERROR("Buffer overflow!"); break; } //Start codes are always byte aligned. bytes_read = read(inputBufferFileFd, &pBuffer[readOffset],1 ); if (!bytes_read) { DEBUG_PRINT("\n Bytes read Zero \n"); break; } total_bytes++; code <<= 8; code |= (0x000000FF & pBufHdr->pBuffer[readOffset]); if (!bSEQflag && (code == VC1_SEQUENCE_START_CODE)) { if (startCode_cnt) bSEQflag = 1; } if (!bEntryflag && ( code == VC1_ENTRY_POINT_START_CODE)) { if (startCode_cnt) bEntryflag = 1; } if (code == VC1_FRAME_START_CODE || code == VC1_FRAME_FIELD_CODE) { startCode_cnt++ ; } //VOP start code comparision if (startCode_cnt == numStartcodes) { if (VC1_FRAME_START_CODE == (code & 0xFFFFFFFF) || VC1_FRAME_FIELD_CODE == (code & 0xFFFFFFFF)) { previous_vc1_au = 0; if (VC1_FRAME_FIELD_CODE == (code & 0xFFFFFFFF)) { previous_vc1_au = 1; } if (!bHdrflag && (bSEQflag || bEntryflag)) { lseek(inputBufferFileFd,-(SEQbytes+4),SEEK_CUR); readOffset -= (SEQbytes+3); } else { //Seek backwards by 4 lseek64(inputBufferFileFd, -4, SEEK_CUR); readOffset-=3; } while (pBufHdr->pBuffer[readOffset-1] == 0) readOffset--; break; } } readOffset++; if (bSEQflag || bEntryflag) { SEQbytes++; } } while (1); pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; #if 0 { int i=0; printf("Read_Buffer_From_VC1_File, readOffset %d\n", readOffset); for (i=0; i<64; i++) { printf("0x%.2x ", pBufHdr->pBuffer[i]); if (i%16 == 15) { printf("\n"); } } printf("\n"); } #endif return readOffset; } static int Read_Buffer_From_DivX_4_5_6_File(OMX_BUFFERHEADERTYPE *pBufHdr) { #define MAX_NO_B_FRMS 3 // Number of non-b-frames packed in each buffer #define N_PREV_FRMS_B 1 // Number of previous non-b-frames packed // with a set of consecutive b-frames #define FRM_ARRAY_SIZE (MAX_NO_B_FRMS + N_PREV_FRMS_B) char *p_buffer = NULL; unsigned int offset_array[FRM_ARRAY_SIZE]; int byte_cntr, pckt_end_idx = 0; unsigned int read_code = 0, bytes_read, byte_pos = 0, frame_type; unsigned int i, b_frm_idx, b_frames_found = 0, vop_set_cntr = 0; bool pckt_ready = false; #ifdef __DEBUG_DIVX__ char pckt_type[20]; int pckd_frms = 0; static unsigned long long int total_bytes = 0; static unsigned long long int total_frames = 0; #endif //__DEBUG_DIVX__ DEBUG_PRINT("Inside %s \n", __FUNCTION__); do { p_buffer = (char *)pBufHdr->pBuffer + byte_pos; bytes_read = read(inputBufferFileFd, p_buffer, NUMBER_OF_ARBITRARYBYTES_READ); byte_pos += bytes_read; for (byte_cntr = 0; byte_cntr < (int)bytes_read && !pckt_ready; byte_cntr++) { read_code <<= 8; ((char*)&read_code)[0] = p_buffer[byte_cntr]; if (read_code == VOP_START_CODE) { if (++byte_cntr < (int)bytes_read) { frame_type = p_buffer[byte_cntr]; frame_type &= 0x000000C0; #ifdef __DEBUG_DIVX__ switch (frame_type) { case 0x00: pckt_type[pckd_frms] = 'I'; break; case 0x40: pckt_type[pckd_frms] = 'P'; break; case 0x80: pckt_type[pckd_frms] = 'B'; break; default: pckt_type[pckd_frms] = 'X'; } pckd_frms++; #endif // __DEBUG_DIVX__ offset_array[vop_set_cntr] = byte_pos - bytes_read + byte_cntr - 4; if (frame_type == 0x80) { // B Frame found! if (!b_frames_found) { // Try to packet N_PREV_FRMS_B previous frames // with the next consecutive B frames i = N_PREV_FRMS_B; while (((int)vop_set_cntr - (int)i) < 0 && i > 0) i--; b_frm_idx = vop_set_cntr - i; if (b_frm_idx > 0) { pckt_end_idx = b_frm_idx; pckt_ready = true; #ifdef __DEBUG_DIVX__ pckt_type[b_frm_idx] = '\0'; total_frames += b_frm_idx; #endif //__DEBUG_DIVX__ } } b_frames_found++; } else if (b_frames_found) { pckt_end_idx = vop_set_cntr; pckt_ready = true; #ifdef __DEBUG_DIVX__ pckt_type[pckd_frms - 1] = '\0'; total_frames += pckd_frms - 1; #endif //__DEBUG_DIVX__ } else if (vop_set_cntr == (FRM_ARRAY_SIZE -1)) { pckt_end_idx = MAX_NO_B_FRMS; pckt_ready = true; #ifdef __DEBUG_DIVX__ pckt_type[pckt_end_idx] = '\0'; total_frames += pckt_end_idx; #endif //__DEBUG_DIVX__ } else vop_set_cntr++; } else { // The vop start code was found in the last 4 bytes, // seek backwards by 4 to include this start code // with the next buffer. lseek64(inputBufferFileFd, -4, SEEK_CUR); byte_pos -= 4; #ifdef __DEBUG_DIVX__ pckd_frms--; #endif //__DEBUG_DIVX__ } } } if (pckt_ready) { loff_t off = (byte_pos - offset_array[pckt_end_idx]); if ( lseek64(inputBufferFileFd, -1LL*off , SEEK_CUR) == -1 ) { DEBUG_PRINT_ERROR("lseek64 with offset = %lld failed with errno %d" ", current position =0x%llx", -1LL*off, errno, lseek64(inputBufferFileFd, 0, SEEK_CUR)); } } else { char eofByte; int ret = read(inputBufferFileFd, &eofByte, 1 ); if ( ret == 0 ) { offset_array[vop_set_cntr] = byte_pos; pckt_end_idx = vop_set_cntr; pckt_ready = true; #ifdef __DEBUG_DIVX__ pckt_type[pckd_frms] = '\0'; total_frames += pckd_frms; #endif //__DEBUG_DIVX__ } else if (ret == 1) { if ( lseek64(inputBufferFileFd, -1, SEEK_CUR ) == -1 ) { DEBUG_PRINT_ERROR("lseek64 failed with errno = %d, " "current fileposition = %llx", errno, lseek64(inputBufferFileFd, 0, SEEK_CUR)); } } else { DEBUG_PRINT_ERROR("Error when checking for EOF"); } } } while (!pckt_ready); pBufHdr->nFilledLen = offset_array[pckt_end_idx]; pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; #ifdef __DEBUG_DIVX__ total_bytes += pBufHdr->nFilledLen; ALOGE("[DivX] Packet: Type[%s] Size[%u] TS[%lld] TB[%llx] NFrms[%lld]\n", pckt_type, pBufHdr->nFilledLen, pBufHdr->nTimeStamp, total_bytes, total_frames); #endif //__DEBUG_DIVX__ return pBufHdr->nFilledLen; } static int Read_Buffer_From_DivX_311_File(OMX_BUFFERHEADERTYPE *pBufHdr) { static OMX_S64 timeStampLfile = 0; char *p_buffer = NULL; bool pkt_ready = false; unsigned int frame_type = 0; unsigned int bytes_read = 0; unsigned int frame_size = 0; unsigned int num_bytes_size = 4; unsigned int num_bytes_frame_type = 1; unsigned int n_offset = pBufHdr->nOffset; DEBUG_PRINT("Inside %s \n", __FUNCTION__); pBufHdr->nTimeStamp = timeStampLfile; if (pBufHdr != NULL) { p_buffer = (char *)pBufHdr->pBuffer + pBufHdr->nOffset; } else { DEBUG_PRINT("\n ERROR:Read_Buffer_From_DivX_311_File: pBufHdr is NULL\n"); return 0; } if (p_buffer == NULL) { DEBUG_PRINT("\n ERROR:Read_Buffer_From_DivX_311_File: p_bufhdr is NULL\n"); return 0; } //Read first frame based on size //DivX 311 frame - 4 byte header with size followed by the frame bytes_read = read(inputBufferFileFd, &frame_size, num_bytes_size); DEBUG_PRINT("Read_Buffer_From_DivX_311_File: Frame size = %d\n", frame_size); n_offset += read(inputBufferFileFd, p_buffer, frame_size); pBufHdr->nTimeStamp = timeStampLfile; timeStampLfile += timestampInterval; //the packet is ready to be sent DEBUG_PRINT("\nReturning Read Buffer from Divx 311: TS=[%ld], Offset=[%d]\n", (long int)pBufHdr->nTimeStamp, n_offset ); return n_offset; } #ifdef _MSM8974_ static int Read_Buffer_From_VP8_File(OMX_BUFFERHEADERTYPE *pBufHdr) { static OMX_S64 timeStampLfile = 0; char *p_buffer = NULL; bool pkt_ready = false; unsigned int frame_type = 0; unsigned int bytes_read = 0; unsigned int frame_size = 0; unsigned int num_bytes_size = 4; unsigned int num_bytes_frame_type = 1; unsigned long long time_stamp; unsigned int n_offset = pBufHdr->nOffset; static int ivf_header_read; if (pBufHdr != NULL) { p_buffer = (char *)pBufHdr->pBuffer + pBufHdr->nOffset; } else { DEBUG_PRINT("\n ERROR:Read_Buffer_From_DivX_311_File: pBufHdr is NULL\n"); return 0; } if (p_buffer == NULL) { DEBUG_PRINT("\n ERROR:Read_Buffer_From_DivX_311_File: p_bufhdr is NULL\n"); return 0; } if (ivf_header_read == 0) { bytes_read = read(inputBufferFileFd, p_buffer, 32); ivf_header_read = 1; if (p_buffer[0] == 'D' && p_buffer[1] == 'K' && p_buffer[2] == 'I' && p_buffer[3] == 'F') { printf(" \n IVF header found \n "); } else { printf(" \n No IVF header found \n "); lseek(inputBufferFileFd, -32, SEEK_CUR); } } bytes_read = read(inputBufferFileFd, &frame_size, 4); bytes_read = read(inputBufferFileFd, &time_stamp, 8); n_offset += read(inputBufferFileFd, p_buffer, frame_size); pBufHdr->nTimeStamp = time_stamp; return n_offset; } static int Read_Buffer_From_MVC_File(OMX_BUFFERHEADERTYPE *pBufHdr) { int newFrame = 0; int bytes_read = 0; int cnt = 0; int naluType = 0; unsigned int code = 0; char *pBuffer = NULL; if (pBufHdr == NULL || pBufHdr->pBuffer == NULL) { DEBUG_PRINT("\n ERROR: %s: input is NULL\n", __FUNCTION__); return 0; } pBuffer = (char *)pBufHdr->pBuffer; pBufHdr->nFilledLen = 0; do { naluType = 0; cnt = 0; code = 0; newFrame = 0; do { bytes_read = read(inputBufferFileFd, &pBuffer[cnt], 1); if (!bytes_read) { DEBUG_PRINT("\n%s: Bytes read Zero\n", __FUNCTION__); break; } else if (cnt == 4) { naluType = pBuffer[cnt] & 0x1F; DEBUG_PRINT("%s: Found NALU type = %d\n", __FUNCTION__, naluType); } code <<= 8; code |= (0x000000FF & pBuffer[cnt]); cnt++; if ((cnt == 4) && (code != H264_START_CODE)) { DEBUG_PRINT_ERROR("\n%s: ERROR: Invalid start code found 0x%x\n", __FUNCTION__, code); lseek64(inputBufferFileFd, -4, SEEK_CUR); cnt = 0; bytes_read = 0; break; } else if ((cnt > 4) && (code == H264_START_CODE)) { DEBUG_PRINT("%s: Found next H264_START_CODE\n", __FUNCTION__); lseek64(inputBufferFileFd, -4, SEEK_CUR); cnt -= 4; break; } if (pBufHdr->nAllocLen <= pBufHdr->nFilledLen + cnt) { DEBUG_PRINT_ERROR("\n%s: ERROR: Invalid input file for MVC codec", __FUNCTION__); cnt = 0; bytes_read = 0; break; } } while (1); pBufHdr->nFilledLen += cnt; pBuffer += cnt; }while (naluType != 20 && bytes_read != 0); pBufHdr->nTimeStamp = 0; pBufHdr->nOffset = 0; DEBUG_PRINT("%s: Return: pBuffer = %p, FilledLen= %ld, TS=[%Lu]\n", __FUNCTION__, pBufHdr->pBuffer, pBufHdr->nFilledLen, pBufHdr->nTimeStamp); return pBufHdr->nFilledLen; } #endif static int open_video_file () { int error_code = 0; char outputfilename[512]; DEBUG_PRINT("Inside %s filename=%s\n", __FUNCTION__, in_filename); if ( (inputBufferFileFd = open( in_filename, O_RDONLY | O_LARGEFILE) ) == -1 ) { DEBUG_PRINT_ERROR("Error - i/p file %s could NOT be opened errno = %d\n", in_filename, errno); error_code = -1; } else { DEBUG_PRINT_ERROR("i/p file %s is opened \n", in_filename); } if (takeYuvLog) { strlcpy(outputfilename, "yuvframes.yuv", 14); outputBufferFile = fopen (outputfilename, "ab"); if (outputBufferFile == NULL) { DEBUG_PRINT_ERROR("ERROR - o/p file %s could NOT be opened\n", outputfilename); error_code = -1; } else { DEBUG_PRINT("O/p file %s is opened \n", outputfilename); } } #ifdef _MSM8974_ /*if (!crcFile) { crcFile = fopen(crclogname, "ab"); if (!crcFile) { printf("Failed to open CRC file\n"); error_code = -1; } }*/ #endif return error_code; } void swap_byte(char *pByte, int nbyte) { int i=0; for (i=0; isrc.width = stride; overlayp->src.height = sliceheight; #ifdef MAX_RES_720P overlayp->src.format = MDP_Y_CRCB_H2V2; if (color_fmt == (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka) { overlayp->src.format = MDP_Y_CRCB_H2V2_TILE; } #endif #ifdef MAX_RES_1080P overlayp->src.format = MDP_Y_CBCR_H2V2_TILE; #endif #ifdef _MSM8974_ overlayp->src.format = MDP_Y_CBCR_H2V2_VENUS; #endif overlayp->src_rect.x = 0; overlayp->src_rect.y = 0; overlayp->src_rect.w = width; overlayp->src_rect.h = height; if (width >= (int)vinfo.xres) { overlayp->dst_rect.x = 0; overlayp->dst_rect.w = vinfo.xres; } else { overlayp->dst_rect.x = (vinfo.xres - width)/2; overlayp->dst_rect.w = width; } if (height >= (int)vinfo.yres) { overlayp->dst_rect.h = (overlayp->dst_rect.w * height)/width; overlayp->dst_rect.y = 0; if (overlayp->dst_rect.h < vinfo.yres) overlayp->dst_rect.y = (vinfo.yres - overlayp->dst_rect.h)/2; else overlayp->dst_rect.h = vinfo.yres; } else { overlayp->dst_rect.y = (vinfo.yres - height)/2; overlayp->dst_rect.h = height; } //Decimation + MDP Downscale overlayp->horz_deci = 0; overlayp->vert_deci = 0; int minHorDeci = 0; if (overlayp->src_rect.w > 2048) { //If the client sends us something > what a layer mixer supports //then it means it doesn't want to use split-pipe but wants us to //decimate. A minimum decimation of 2 will ensure that the width is //always within layer mixer limits. minHorDeci = 2; } float horDscale = ceilf((float)overlayp->src_rect.w / (float)overlayp->dst_rect.w); float verDscale = ceilf((float)overlayp->src_rect.h / (float)overlayp->dst_rect.h); //Next power of 2, if not already horDscale = powf(2.0f, ceilf(log2f(horDscale))); verDscale = powf(2.0f, ceilf(log2f(verDscale))); //Since MDP can do 1/4 dscale and has better quality, split the task //between decimator and MDP downscale horDscale /= 4.0f; verDscale /= 4.0f; if (horDscale < minHorDeci) horDscale = minHorDeci; if ((int)horDscale) overlayp->horz_deci = (int)log2f(horDscale); if ((int)verDscale) overlayp->vert_deci = (int)log2f(verDscale); printf("overlayp->src.width = %u \n", overlayp->src.width); printf("overlayp->src.height = %u \n", overlayp->src.height); printf("overlayp->src_rect.x = %u \n", overlayp->src_rect.x); printf("overlayp->src_rect.y = %u \n", overlayp->src_rect.y); printf("overlayp->src_rect.w = %u \n", overlayp->src_rect.w); printf("overlayp->src_rect.h = %u \n", overlayp->src_rect.h); printf("overlayp->dst_rect.x = %u \n", overlayp->dst_rect.x); printf("overlayp->dst_rect.y = %u \n", overlayp->dst_rect.y); printf("overlayp->dst_rect.w = %u \n", overlayp->dst_rect.w); printf("overlayp->dst_rect.h = %u \n", overlayp->dst_rect.h); printf("overlayp->vert_deci = %u \n", overlayp->vert_deci); printf("overlayp->horz_deci = %u \n", overlayp->horz_deci); overlayp->z_order = 0; overlayp->alpha = 0xff; overlayp->transp_mask = 0xFFFFFFFF; overlayp->flags = 0; overlayp->is_fg = 0; overlayp->id = MSMFB_NEW_REQUEST; overlay_vsync_ctrl(OMX_TRUE); drawBG(); vid_buf_front_id = ioctl(fb_fd, MSMFB_OVERLAY_SET, overlayp); if (vid_buf_front_id < 0) { printf("ERROR: MSMFB_OVERLAY_SET failed! line=%d\n", __LINE__); } vid_buf_front_id = overlayp->id; DEBUG_PRINT("\n vid_buf_front_id = %u", vid_buf_front_id); displayYuv = 2; } int overlay_fb(struct OMX_BUFFERHEADERTYPE *pBufHdr) { OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; struct msmfb_overlay_data ov_front; memset(&ov_front, 0, sizeof(struct msmfb_overlay_data)); #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) MemoryHeapBase *vheap = NULL; #endif DEBUG_PRINT("overlay_fb:"); ov_front.id = overlayp->id; if (pBufHdr->pPlatformPrivate == NULL) { ALOGE("overlay_fb: pPlatformPrivate is null"); return -1; } pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) ((OMX_QCOM_PLATFORM_PRIVATE_LIST *) pBufHdr->pPlatformPrivate)->entryList->entry; if (pPMEMInfo == NULL) { ALOGE("overlay_fb: pmem_info is null"); return -1; } #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) vheap = (MemoryHeapBase*)pPMEMInfo->pmem_fd; #endif #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) && !defined(_MSM8974_) ov_front.data.memory_id = vheap->getHeapID(); #else ov_front.data.memory_id = pPMEMInfo->pmem_fd; #endif ov_front.data.offset = pPMEMInfo->offset; DEBUG_PRINT("\n ov_front.data.memory_id = %d", ov_front.data.memory_id); DEBUG_PRINT("\n ov_front.data.offset = %u", ov_front.data.offset); if (ioctl(fb_fd, MSMFB_OVERLAY_PLAY, (void*)&ov_front)) { printf("\nERROR! MSMFB_OVERLAY_PLAY failed at frame (Line %d)\n", __LINE__); return -1; } if (ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo) < 0) { printf("ERROR: FBIOPAN_DISPLAY failed! line=%d\n", __LINE__); return -1; } DEBUG_PRINT("\nMSMFB_OVERLAY_PLAY successfull"); return 0; } void overlay_unset() { if (ioctl(fb_fd, MSMFB_OVERLAY_UNSET, &vid_buf_front_id)) { printf("\nERROR! MSMFB_OVERLAY_UNSET failed! (Line %d)\n", __LINE__); } } void render_fb(struct OMX_BUFFERHEADERTYPE *pBufHdr) { unsigned int addr = 0; OMX_OTHER_EXTRADATATYPE *pExtraData = 0; OMX_QCOM_EXTRADATA_FRAMEINFO *pExtraFrameInfo = 0; OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *pPMEMInfo = NULL; unsigned int destx, desty,destW, destH; #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) MemoryHeapBase *vheap = NULL; #endif unsigned int end = (unsigned int)(pBufHdr->pBuffer + pBufHdr->nAllocLen); struct mdp_blit_req *e; union { char dummy[sizeof(struct mdp_blit_req_list) + sizeof(struct mdp_blit_req) * 1]; struct mdp_blit_req_list list; } img; if (fb_fd < 0) { DEBUG_PRINT_ERROR("Warning: /dev/fb0 is not opened!\n"); return; } img.list.count = 1; e = &img.list.req[0]; addr = (unsigned int)(pBufHdr->pBuffer + pBufHdr->nFilledLen); // align to a 4 byte boundary addr = (addr + 3) & (~3); // read to the end of existing extra data sections pExtraData = (OMX_OTHER_EXTRADATATYPE*)addr; while (addr < end && (int)pExtraData->eType != (int)OMX_ExtraDataFrameInfo) { addr += pExtraData->nSize; pExtraData = (OMX_OTHER_EXTRADATATYPE*)addr; } if ((int)pExtraData->eType != (int)OMX_ExtraDataFrameInfo) { DEBUG_PRINT_ERROR("pExtraData->eType %d pExtraData->nSize %u\n",pExtraData->eType, (unsigned int)pExtraData->nSize); } pExtraFrameInfo = (OMX_QCOM_EXTRADATA_FRAMEINFO *)pExtraData->data; pPMEMInfo = (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO *) ((OMX_QCOM_PLATFORM_PRIVATE_LIST *) pBufHdr->pPlatformPrivate)->entryList->entry; #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) vheap = (MemoryHeapBase *)pPMEMInfo->pmem_fd; #endif DEBUG_PRINT_ERROR("DecWidth %u DecHeight %u\n",(unsigned int)portFmt.format.video.nStride,(unsigned int)portFmt.format.video.nSliceHeight); DEBUG_PRINT_ERROR("DispWidth %u DispHeight %u\n",(unsigned int)portFmt.format.video.nFrameWidth,(unsigned int)portFmt.format.video.nFrameHeight); e->src.width = portFmt.format.video.nStride; e->src.height = portFmt.format.video.nSliceHeight; e->src.format = MDP_Y_CBCR_H2V2; e->src.offset = pPMEMInfo->offset; #if defined(_ANDROID_) && !defined(USE_EGL_IMAGE_TEST_APP) && !defined(USE_EXTERN_PMEM_BUF) e->src.memory_id = vheap->getHeapID(); #else e->src.memory_id = pPMEMInfo->pmem_fd; #endif DEBUG_PRINT_ERROR("pmemOffset %d pmemID %d\n",e->src.offset,e->src.memory_id); e->dst.width = vinfo.xres; e->dst.height = vinfo.yres; e->dst.format = MDP_RGB_565; e->dst.offset = 0; e->dst.memory_id = fb_fd; e->transp_mask = 0xffffffff; DEBUG_PRINT("Frame interlace type %d!\n", pExtraFrameInfo->interlaceType); if (pExtraFrameInfo->interlaceType != OMX_QCOM_InterlaceFrameProgressive) { DEBUG_PRINT("Interlaced Frame!\n"); e->flags = MDP_DEINTERLACE; } else e->flags = 0; e->alpha = 0xff; switch (displayWindow) { case 1: destx = 0; desty = 0; destW = vinfo.xres/2; destH = vinfo.yres/2; break; case 2: destx = vinfo.xres/2; desty = 0; destW = vinfo.xres/2; destH = vinfo.yres/2; break; case 3: destx = 0; desty = vinfo.yres/2; destW = vinfo.xres/2; destH = vinfo.yres/2; break; case 4: destx = vinfo.xres/2; desty = vinfo.yres/2; destW = vinfo.xres/2; destH = vinfo.yres/2; break; case 0: default: destx = 0; desty = 0; destW = vinfo.xres; destH = vinfo.yres; } if (portFmt.format.video.nFrameWidth < destW) destW = portFmt.format.video.nFrameWidth ; if (portFmt.format.video.nFrameHeight < destH) destH = portFmt.format.video.nFrameHeight; e->dst_rect.x = destx; e->dst_rect.y = desty; e->dst_rect.w = destW; e->dst_rect.h = destH; //e->dst_rect.w = 800; //e->dst_rect.h = 480; e->src_rect.x = 0; e->src_rect.y = 0; e->src_rect.w = portFmt.format.video.nFrameWidth; e->src_rect.h = portFmt.format.video.nFrameHeight; //e->src_rect.w = portFmt.format.video.nStride; //e->src_rect.h = portFmt.format.video.nSliceHeight; if (ioctl(fb_fd, MSMFB_BLIT, &img)) { DEBUG_PRINT_ERROR("MSMFB_BLIT ioctl failed!\n"); return; } if (ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo) < 0) { DEBUG_PRINT_ERROR("FBIOPAN_DISPLAY failed! line=%d\n", __LINE__); return; } DEBUG_PRINT("render_fb complete!\n"); } int disable_output_port() { DEBUG_PRINT("DISABLING OP PORT\n"); pthread_mutex_lock(&enable_lock); sent_disabled = 1; // Send DISABLE command OMX_SendCommand(dec_handle, OMX_CommandPortDisable, 1, 0); pthread_mutex_unlock(&enable_lock); // wait for Disable event to come back wait_for_event(); if (p_eglHeaders) { free(p_eglHeaders); p_eglHeaders = NULL; } if (pPMEMInfo) { DEBUG_PRINT("Freeing in external pmem case:PMEM"); free(pPMEMInfo); pPMEMInfo = NULL; } if (pPlatformEntry) { DEBUG_PRINT("Freeing in external pmem case:ENTRY"); free(pPlatformEntry); pPlatformEntry = NULL; } if (pPlatformList) { DEBUG_PRINT("Freeing in external pmem case:LIST"); free(pPlatformList); pPlatformList = NULL; } if (currentStatus == ERROR_STATE) { do_freeHandle_and_clean_up(true); return -1; } DEBUG_PRINT("OP PORT DISABLED!\n"); return 0; } int enable_output_port() { unsigned int bufCnt = 0; OMX_ERRORTYPE ret = OMX_ErrorNone; DEBUG_PRINT("ENABLING OP PORT\n"); if (currentStatus == ERROR_STATE) { DEBUG_PRINT("ENABLING OP PORT in ERROR_STATE not allowed\n"); return -1; } // Send Enable command OMX_SendCommand(dec_handle, OMX_CommandPortEnable, 1, 0); #ifndef USE_EGL_IMAGE_TEST_APP /* Allocate buffer on decoder's o/p port */ portFmt.nPortIndex = 1; if (anti_flickering) { ret = OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); if (ret != OMX_ErrorNone) { DEBUG_PRINT_ERROR("%s: OMX_GetParameter failed: %d",__FUNCTION__, ret); return -1; } portFmt.nBufferCountActual += 1; ret = OMX_SetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); if (ret != OMX_ErrorNone) { DEBUG_PRINT_ERROR("%s: OMX_SetParameter failed: %d",__FUNCTION__, ret); return -1; } } if (use_external_pmem_buf) { DEBUG_PRINT("Enable op port: calling use_buffer_mult_fd\n"); error = use_output_buffer_multiple_fd(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferSize, portFmt.nBufferCountActual); } else { error = Allocate_Buffer(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferCountActual, portFmt.nBufferSize); } if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("Error - OMX_AllocateBuffer Output buffer error\n"); return -1; } else { DEBUG_PRINT("OMX_AllocateBuffer Output buffer success\n"); free_op_buf_cnt = portFmt.nBufferCountActual; } #else error = use_output_buffer(dec_handle, &pOutYUVBufHdrs, portFmt.nPortIndex, portFmt.nBufferSize, portFmt.nBufferCountActual); free_op_buf_cnt = portFmt.nBufferCountActual; if (error != OMX_ErrorNone) { DEBUG_PRINT_ERROR("ERROR - OMX_UseBuffer Input buffer failed"); return -1; } else { DEBUG_PRINT("OMX_UseBuffer Input buffer success\n"); } #endif // wait for enable event to come back wait_for_event(); if (currentStatus == ERROR_STATE) { do_freeHandle_and_clean_up(true); return -1; } if (pOutYUVBufHdrs == NULL) { DEBUG_PRINT_ERROR("Error - pOutYUVBufHdrs is NULL\n"); return -1; } for (bufCnt=0; bufCnt < portFmt.nBufferCountActual; ++bufCnt) { DEBUG_PRINT("OMX_FillThisBuffer on output buf no.%d\n",bufCnt); if (pOutYUVBufHdrs[bufCnt] == NULL) { DEBUG_PRINT_ERROR("Error - pOutYUVBufHdrs[%d] is NULL\n", bufCnt); return -1; } pOutYUVBufHdrs[bufCnt]->nOutputPortIndex = 1; pOutYUVBufHdrs[bufCnt]->nFlags &= ~OMX_BUFFERFLAG_EOS; ret = OMX_FillThisBuffer(dec_handle, pOutYUVBufHdrs[bufCnt]); if (OMX_ErrorNone != ret) { DEBUG_PRINT_ERROR("ERROR - OMX_FillThisBuffer failed with result %d\n", ret); } else { DEBUG_PRINT("OMX_FillThisBuffer success!\n"); free_op_buf_cnt--; } } DEBUG_PRINT("OP PORT ENABLED!\n"); return 0; } int output_port_reconfig() { DEBUG_PRINT("PORT_SETTING_CHANGE_STATE\n"); if (disable_output_port() != 0) return -1; /* Port for which the Client needs to obtain info */ portFmt.nPortIndex = 1; OMX_GetParameter(dec_handle,OMX_IndexParamPortDefinition,&portFmt); DEBUG_PRINT("Min Buffer Count=%d", portFmt.nBufferCountMin); DEBUG_PRINT("Buffer Size=%d", portFmt.nBufferSize); if (OMX_DirOutput != portFmt.eDir) { DEBUG_PRINT_ERROR("Error - Expect Output Port\n"); return -1; } height = portFmt.format.video.nFrameHeight; width = portFmt.format.video.nFrameWidth; stride = portFmt.format.video.nStride; sliceheight = portFmt.format.video.nSliceHeight; crop_rect.nWidth = width; crop_rect.nHeight = height; if (displayYuv == 2) { DEBUG_PRINT("Reconfiguration at middle of playback..."); close_display(); if (open_display() != 0) { printf("\n Error opening display! Video won't be displayed..."); displayYuv = 0; } } if (displayYuv) overlay_set(); if (enable_output_port() != 0) return -1; DEBUG_PRINT("PORT_SETTING_CHANGE DONE!\n"); return 0; } void free_output_buffers() { int index = 0; OMX_BUFFERHEADERTYPE *pBuffer = (OMX_BUFFERHEADERTYPE *)pop(fbd_queue); while (pBuffer) { DEBUG_PRINT("\n pOutYUVBufHdrs %p p_eglHeaders %p output_use_buffer %d", pOutYUVBufHdrs,p_eglHeaders,output_use_buffer); if (pOutYUVBufHdrs && p_eglHeaders && output_use_buffer) { index = pBuffer - pOutYUVBufHdrs[0]; DEBUG_PRINT("\n Index of free buffer %d",index); DEBUG_PRINT("\n Address freed %p size freed %d",pBuffer->pBuffer, pBuffer->nAllocLen); munmap((void *)use_buf_virt_addr[index],pBuffer->nAllocLen); if (p_eglHeaders[index]) { close(p_eglHeaders[index]->pmem_fd); free(p_eglHeaders[index]); p_eglHeaders[index] = NULL; } } if (pOutYUVBufHdrs && use_external_pmem_buf) { index = pBuffer - pOutYUVBufHdrs[0]; DEBUG_PRINT("\n Address freed %p size freed %d,virt=0x%x,pmem_fd=0x%x", pBuffer->pBuffer, pBuffer->nAllocLen, use_buf_virt_addr[index], pPMEMInfo[index].pmem_fd); munmap((void *)use_buf_virt_addr[index],pBuffer->nAllocLen); getFreePmem(); use_buf_virt_addr[index] = -1; if (&pPMEMInfo[index]) { close(pPMEMInfo[index].pmem_fd); pPMEMInfo[index].pmem_fd = -1; } } DEBUG_PRINT("\n Free output buffer"); OMX_FreeBuffer(dec_handle, 1, pBuffer); pBuffer = (OMX_BUFFERHEADERTYPE *)pop(fbd_queue); } } #ifndef USE_ION static bool align_pmem_buffers(int pmem_fd, OMX_U32 buffer_size, OMX_U32 alignment) { struct pmem_allocation allocation; allocation.size = buffer_size; allocation.align = clip2(alignment); if (allocation.align < 4096) { allocation.align = 4096; } if (ioctl(pmem_fd, PMEM_ALLOCATE_ALIGNED, &allocation) < 0) { DEBUG_PRINT_ERROR("\n Aligment failed with pmem driver"); return false; } return true; } #endif int open_display() { #ifdef _ANDROID_ DEBUG_PRINT("\n Opening /dev/graphics/fb0"); fb_fd = open("/dev/graphics/fb0", O_RDWR); #else DEBUG_PRINT("\n Opening /dev/fb0"); fb_fd = open("/dev/fb0", O_RDWR); #endif if (fb_fd < 0) { printf("[omx_vdec_test] - ERROR - can't open framebuffer!\n"); return -1; } DEBUG_PRINT("\n fb_fd = %d", fb_fd); if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0) { printf("[omx_vdec_test] - ERROR - can't retrieve fscreenInfo!\n"); close(fb_fd); return -1; } if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) { printf("[omx_vdec_test] - ERROR - can't retrieve vscreenInfo!\n"); close(fb_fd); return -1; } printf("Display xres = %d, yres = %d \n", vinfo.xres, vinfo.yres); return 0; } void close_display() { overlay_unset(); overlay_vsync_ctrl(OMX_FALSE); close(fb_fd); fb_fd = -1; } void getFreePmem() { #ifndef USE_ION int ret = -1; /*Open pmem device and query free pmem*/ int pmem_fd = open (PMEM_DEVICE,O_RDWR); if (pmem_fd < 0) { ALOGE("Unable to open pmem device"); return; } struct pmem_freespace fs; ret = ioctl(pmem_fd, PMEM_GET_FREE_SPACE, &fs); if (ret) { ALOGE("IOCTL to query pmem free space failed"); goto freespace_query_failed; } ALOGE("Available free space %lx largest chunk %lx\n", fs.total, fs.largest); freespace_query_failed: close(pmem_fd); #endif }