/*-------------------------------------------------------------------------- Copyright (c) 2010-2013, 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. --------------------------------------------------------------------------*/ /*============================================================================ V E N C _ T E S T. C P P DESCRIPTION This is the OMX test app . REFERENCES ============================================================================*/ //usage // FILE QVGA MP4 24 384000 100 enc_qvga.yuv QVGA_24.m4v // FILE QCIF MP4 15 96000 0 foreman.qcif.yuv output_qcif.m4v // FILE VGA MP4 24 1200000 218 enc_vga.yuv vga_output.m4v #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <fcntl.h> #include <sys/mman.h> //#include <sys/time.h> #include <time.h> #include <sys/ioctl.h> #include <limits.h> #include <string.h> //#include <sys/stat.h> #include "OMX_QCOMExtns.h" #include "OMX_Core.h" #define QCOM_EXT 1 #include "OMX_Core.h" #include "OMX_Video.h" #include "OMX_Component.h" #include "camera_test.h" #include "fb_test.h" #include "venc_util.h" #include "extra_data_handler.h" #ifdef USE_ION #include <linux/msm_ion.h> #endif #ifdef _MSM8974_ #include <media/msm_media_info.h> #endif ////////////////////////// // MACROS ////////////////////////// #define CHK(result) if ((result != OMX_ErrorNone) && (result != OMX_ErrorNoMore)) { E("*************** error *************"); exit(0); } #define TEST_LOG #ifdef VENC_SYSLOG #include <cutils/log.h> /// Debug message macro #define D(fmt, ...) ALOGE("venc_test Debug %s::%d "fmt, \ __FUNCTION__, __LINE__, \ ## __VA_ARGS__) /// Error message macro #define E(fmt, ...) ALOGE("venc_test Error %s::%d "fmt, \ __FUNCTION__, __LINE__, \ ## __VA_ARGS__) #else #ifdef TEST_LOG #define D(fmt, ...) fprintf(stderr, "venc_test Debug %s::%d "fmt"\n", \ __FUNCTION__, __LINE__, \ ## __VA_ARGS__) /// Error message macro #define E(fmt, ...) fprintf(stderr, "venc_test Error %s::%d "fmt"\n", \ __FUNCTION__, __LINE__, \ ## __VA_ARGS__) #else #define D(fmt, ...) #define E(fmt, ...) #endif #endif ////////////////////////// // CONSTANTS ////////////////////////// static const int MAX_MSG = 100; //#warning do not hardcode these use port definition static const int PORT_INDEX_IN = 0; static const int PORT_INDEX_OUT = 1; static const int NUM_IN_BUFFERS = 10; static const int NUM_OUT_BUFFERS = 10; unsigned int num_in_buffers = 0; unsigned int num_out_buffers = 0; ////////////////////////// /* MPEG4 profile and level table*/ static const unsigned int mpeg4_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileSimple}, {99,1485,64000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileSimple}, {396,5940,128000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileSimple}, {396,11880,384000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileSimple}, {1200,36000,4000000,OMX_VIDEO_MPEG4Level4a,OMX_VIDEO_MPEG4ProfileSimple}, {1620,40500,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, {3600,108000,12000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, {34560,1036800,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileSimple}, #endif {0,0,0,0,0}, {99,1485,128000,OMX_VIDEO_MPEG4Level0,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {99,1485,128000,OMX_VIDEO_MPEG4Level1,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {396,5940,384000,OMX_VIDEO_MPEG4Level2,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {396,11880,768000,OMX_VIDEO_MPEG4Level3,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {792,23760,3000000,OMX_VIDEO_MPEG4Level4,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {1620,48600,8000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, {34560,1036800,20000000,OMX_VIDEO_MPEG4Level5,OMX_VIDEO_MPEG4ProfileAdvancedSimple}, #endif {0,0,0,0,0}, }; /* H264 profile and level table*/ static const unsigned int h264_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileBaseline}, {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileBaseline}, {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileBaseline}, {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileBaseline}, {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileBaseline}, {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileBaseline}, {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileBaseline}, {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileBaseline}, {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileBaseline}, {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileBaseline}, {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileBaseline}, {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline}, {34560,1036800,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileBaseline}, #endif {0,0,0,0,0}, {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileHigh}, {99,1485,160000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileHigh}, {396,3000,240000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileHigh}, {396,6000,480000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileHigh}, {396,11880,960000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileHigh}, {396,11880,2500000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileHigh}, {792,19800,5000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileHigh}, {1620,20250,5000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileHigh}, {1620,40500,12500000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileHigh}, {3600,108000,17500000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileHigh}, {5120,216000,25000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileHigh}, {8192,245760,25000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh}, {34560,1036800,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileHigh}, #endif {0,0,0,0,0}, {99,1485,64000,OMX_VIDEO_AVCLevel1,OMX_VIDEO_AVCProfileMain}, {99,1485,128000,OMX_VIDEO_AVCLevel1b,OMX_VIDEO_AVCProfileMain}, {396,3000,192000,OMX_VIDEO_AVCLevel11,OMX_VIDEO_AVCProfileMain}, {396,6000,384000,OMX_VIDEO_AVCLevel12,OMX_VIDEO_AVCProfileMain}, {396,11880,768000,OMX_VIDEO_AVCLevel13,OMX_VIDEO_AVCProfileMain}, {396,11880,2000000,OMX_VIDEO_AVCLevel2,OMX_VIDEO_AVCProfileMain}, {792,19800,4000000,OMX_VIDEO_AVCLevel21,OMX_VIDEO_AVCProfileMain}, {1620,20250,4000000,OMX_VIDEO_AVCLevel22,OMX_VIDEO_AVCProfileMain}, {1620,40500,10000000,OMX_VIDEO_AVCLevel3,OMX_VIDEO_AVCProfileMain}, {3600,108000,14000000,OMX_VIDEO_AVCLevel31,OMX_VIDEO_AVCProfileMain}, {5120,216000,20000000,OMX_VIDEO_AVCLevel32,OMX_VIDEO_AVCProfileMain}, {8192,245760,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain}, {34560,1036800,20000000,OMX_VIDEO_AVCLevel4,OMX_VIDEO_AVCProfileMain}, #endif {0,0,0,0,0} }; /* H263 profile and level table*/ static const unsigned int h263_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_H263Level10,OMX_VIDEO_H263ProfileBaseline}, {396,5940,128000,OMX_VIDEO_H263Level20,OMX_VIDEO_H263ProfileBaseline}, {396,11880,384000,OMX_VIDEO_H263Level30,OMX_VIDEO_H263ProfileBaseline}, {396,11880,2048000,OMX_VIDEO_H263Level40,OMX_VIDEO_H263ProfileBaseline}, {99,1485,128000,OMX_VIDEO_H263Level45,OMX_VIDEO_H263ProfileBaseline}, {396,19800,4096000,OMX_VIDEO_H263Level50,OMX_VIDEO_H263ProfileBaseline}, {810,40500,8192000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline}, {1620,81000,16384000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, #ifdef _MSM8974_ {32400,972000,20000000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline}, {34560,1036800,20000000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, #endif {0,0,0,0,0} }; #ifdef _MSM8974_ static const unsigned int VP8_profile_level_table[][5]= { /*max mb per frame, max mb per sec, max bitrate, level, profile*/ {99,1485,64000,OMX_VIDEO_H263Level10,OMX_VIDEO_H263ProfileBaseline}, {396,5940,128000,OMX_VIDEO_H263Level20,OMX_VIDEO_H263ProfileBaseline}, {396,11880,384000,OMX_VIDEO_H263Level30,OMX_VIDEO_H263ProfileBaseline}, {396,11880,2048000,OMX_VIDEO_H263Level40,OMX_VIDEO_H263ProfileBaseline}, {99,1485,128000,OMX_VIDEO_H263Level45,OMX_VIDEO_H263ProfileBaseline}, {396,19800,4096000,OMX_VIDEO_H263Level50,OMX_VIDEO_H263ProfileBaseline}, {810,40500,8192000,OMX_VIDEO_H263Level60,OMX_VIDEO_H263ProfileBaseline}, {1620,81000,16384000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, {32400,972000,20000000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, {34560,1036800,20000000,OMX_VIDEO_H263Level70,OMX_VIDEO_H263ProfileBaseline}, {0,0,0,0,0} }; #endif #define Log2(number, power) { OMX_U32 temp = number; power = 0; while( (0 == (temp & 0x1)) && power < 16) { temp >>=0x1; power++; } } #define FractionToQ16(q,num,den) { OMX_U32 power; Log2(den,power); q = num << (16 - power); } ////////////////////////// // TYPES ////////////////////////// struct ProfileType { OMX_VIDEO_CODINGTYPE eCodec; OMX_VIDEO_MPEG4LEVELTYPE eLevel; OMX_VIDEO_CONTROLRATETYPE eControlRate; OMX_VIDEO_AVCSLICEMODETYPE eSliceMode; OMX_U32 nFrameWidth; OMX_U32 nFrameHeight; OMX_U32 nFrameBytes; #ifdef _MSM8974_ OMX_U32 nFramestride; OMX_U32 nFrameScanlines; OMX_U32 nFrameRead; #endif OMX_U32 nBitrate; float nFramerate; char* cInFileName; char* cOutFileName; OMX_U32 nUserProfile; }; enum MsgId { MSG_ID_OUTPUT_FRAME_DONE, MSG_ID_INPUT_FRAME_DONE, MSG_ID_MAX }; union MsgData { struct { OMX_BUFFERHEADERTYPE* pBuffer; } sBitstreamData; }; struct Msg { MsgId id; MsgData data; }; struct MsgQ { Msg q[MAX_MSG]; int head; int size; }; enum Mode { MODE_PREVIEW, MODE_DISPLAY, MODE_PROFILE, MODE_FILE_ENCODE, MODE_LIVE_ENCODE }; enum ResyncMarkerType { RESYNC_MARKER_NONE, ///< No resync marker RESYNC_MARKER_BYTE, ///< BYTE Resync marker for MPEG4, H.264 RESYNC_MARKER_MB, ///< MB resync marker for MPEG4, H.264 RESYNC_MARKER_GOB ///< GOB resync marker for H.263 }; union DynamicConfigData { OMX_VIDEO_CONFIG_BITRATETYPE bitrate; OMX_CONFIG_FRAMERATETYPE framerate; QOMX_VIDEO_INTRAPERIODTYPE intraperiod; OMX_CONFIG_INTRAREFRESHVOPTYPE intravoprefresh; OMX_CONFIG_ROTATIONTYPE rotation; float f_framerate; }; struct DynamicConfig { bool pending; unsigned frame_num; OMX_INDEXTYPE config_param; union DynamicConfigData config_data; }; #ifdef USE_ION struct enc_ion { int ion_device_fd; struct ion_allocation_data alloc_data; struct ion_fd_data ion_alloc_fd; }; #endif ////////////////////////// // MODULE VARS ////////////////////////// static pthread_mutex_t m_mutex; static pthread_cond_t m_signal; static MsgQ m_sMsgQ; //#warning determine how many buffers we really have OMX_STATETYPE m_eState = OMX_StateInvalid; OMX_COMPONENTTYPE m_sComponent; OMX_HANDLETYPE m_hHandle = NULL; OMX_BUFFERHEADERTYPE* m_pOutBuffers[NUM_OUT_BUFFERS] = {NULL}; OMX_BUFFERHEADERTYPE* m_pInBuffers[NUM_IN_BUFFERS] = {NULL}; OMX_BOOL m_bInFrameFree[NUM_IN_BUFFERS]; ProfileType m_sProfile; static int m_nFramePlay = 0; static int m_eMode = MODE_PREVIEW; static int m_nInFd = -1; static int m_nOutFd = -1; static int m_nTimeStamp = 0; static int m_nFrameIn = 0; // frames pushed to encoder static int m_nFrameOut = 0; // frames returned by encoder static int m_nAVCSliceMode = 0; static bool m_bWatchDogKicked = false; FILE *m_pDynConfFile = NULL; static struct DynamicConfig dynamic_config; /* Statistics Logging */ static long long tot_bufsize = 0; int ebd_cnt=0, fbd_cnt=0; #ifdef USE_ION static const char* PMEM_DEVICE = "/dev/ion"; #elif MAX_RES_720P static const char* PMEM_DEVICE = "/dev/pmem_adsp"; #elif MAX_RES_1080P_EBI static const char* PMEM_DEVICE = "/dev/pmem_adsp"; #elif MAX_RES_1080P static const char* PMEM_DEVICE = "/dev/pmem_smipool"; #else #error PMEM_DEVICE cannot be determined. #endif #ifdef USE_ION struct enc_ion ion_data; #endif ////////////////////////// // MODULE FUNCTIONS ////////////////////////// void* PmemMalloc(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO* pMem, int nSize) { void *pvirt = NULL; int rc = 0; if (!pMem) return NULL; #ifdef USE_ION ion_data.ion_device_fd = open (PMEM_DEVICE, O_RDONLY); if (ion_data.ion_device_fd < 0) { E("\nERROR: ION Device open() Failed"); return NULL; } nSize = (nSize + 4095) & (~4095); ion_data.alloc_data.len = nSize; ion_data.alloc_data.heap_id_mask = 0x1 << ION_CP_MM_HEAP_ID; ion_data.alloc_data.align = 4096; ion_data.alloc_data.flags = ION_SECURE; rc = ioctl(ion_data.ion_device_fd,ION_IOC_ALLOC,&ion_data.alloc_data); if (rc || !ion_data.alloc_data.handle) { E("\n ION ALLOC memory failed rc: %d, handle: %p", rc, ion_data.alloc_data.handle); ion_data.alloc_data.handle=NULL; return NULL; } ion_data.ion_alloc_fd.handle = ion_data.alloc_data.handle; rc = ioctl(ion_data.ion_device_fd,ION_IOC_MAP,&ion_data.ion_alloc_fd); if (rc) { E("\n ION MAP failed "); ion_data.ion_alloc_fd.fd =-1; ion_data.ion_alloc_fd.fd =-1; return NULL; } pMem->pmem_fd = ion_data.ion_alloc_fd.fd; #else pMem->pmem_fd = open(PMEM_DEVICE, O_RDWR); if ((int)(pMem->pmem_fd) < 0) return NULL; nSize = (nSize + 4095) & (~4095); #endif pMem->offset = 0; pvirt = mmap(NULL, nSize, PROT_READ | PROT_WRITE, MAP_SHARED, pMem->pmem_fd, pMem->offset); if (pvirt == (void*) MAP_FAILED) { close(pMem->pmem_fd); pMem->pmem_fd = -1; #ifdef USE_ION if (ioctl(ion_data.ion_device_fd,ION_IOC_FREE, &ion_data.alloc_data.handle)) { E("ion recon buffer free failed"); } ion_data.alloc_data.handle = NULL; ion_data.ion_alloc_fd.fd =-1; close(ion_data.ion_device_fd); ion_data.ion_device_fd =-1; #endif return NULL; } D("allocated pMem->fd = %lu pvirt=0x%p, pMem->phys=0x%lx, size = %d", pMem->pmem_fd, pvirt, pMem->offset, nSize); return pvirt; } int PmemFree(OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO* pMem, void* pvirt, int nSize) { if (!pMem || !pvirt) return -1; nSize = (nSize + 4095) & (~4095); munmap(pvirt, nSize); close(pMem->pmem_fd); pMem->pmem_fd = -1; #ifdef USE_ION if (ioctl(ion_data.ion_device_fd,ION_IOC_FREE, &ion_data.alloc_data.handle)) { E("ion recon buffer free failed"); } ion_data.alloc_data.handle = NULL; ion_data.ion_alloc_fd.fd =-1; close(ion_data.ion_device_fd); ion_data.ion_device_fd =-1; #endif return 0; } void PrintFramePackArrangement(OMX_QCOM_FRAME_PACK_ARRANGEMENT framePackingArrangement) { printf("id (%lu)\n", framePackingArrangement.id); printf("cancel_flag (%lu)\n", framePackingArrangement.cancel_flag); printf("type (%lu)\n", framePackingArrangement.type); printf("quincunx_sampling_flag (%lu)\n", framePackingArrangement.quincunx_sampling_flag); printf("content_interpretation_type (%lu)\n", framePackingArrangement.content_interpretation_type); printf("spatial_flipping_flag (%lu)\n", framePackingArrangement.spatial_flipping_flag); printf("frame0_flipped_flag (%lu)\n", framePackingArrangement.frame0_flipped_flag); printf("field_views_flag (%lu)\n", framePackingArrangement.field_views_flag); printf("current_frame_is_frame0_flag (%lu)\n", framePackingArrangement.current_frame_is_frame0_flag); printf("frame0_self_contained_flag (%lu)\n", framePackingArrangement.frame0_self_contained_flag); printf("frame1_self_contained_flag (%lu)\n", framePackingArrangement.frame1_self_contained_flag); printf("frame0_grid_position_x (%lu)\n", framePackingArrangement.frame0_grid_position_x); printf("frame0_grid_position_y (%lu)\n", framePackingArrangement.frame0_grid_position_y); printf("frame1_grid_position_x (%lu)\n", framePackingArrangement.frame1_grid_position_x); printf("frame1_grid_position_y (%lu)\n", framePackingArrangement.frame1_grid_position_y); printf("reserved_byte (%lu)\n", framePackingArrangement.reserved_byte); printf("repetition_period (%lu)\n", framePackingArrangement.repetition_period); printf("extension_flag (%lu)\n", framePackingArrangement.extension_flag); } void SetState(OMX_STATETYPE eState) { #define GOTO_STATE(eState) \ case eState: \ { \ D("Going to state " # eState"..."); \ OMX_SendCommand(m_hHandle, \ OMX_CommandStateSet, \ (OMX_U32) eState, \ NULL); \ while (m_eState != eState) \ { \ sleep(1); \ } \ D("Now in state " # eState); \ break; \ } switch (eState) { GOTO_STATE(OMX_StateLoaded); GOTO_STATE(OMX_StateIdle); GOTO_STATE(OMX_StateExecuting); GOTO_STATE(OMX_StateInvalid); GOTO_STATE(OMX_StateWaitForResources); GOTO_STATE(OMX_StatePause); } } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE ConfigureEncoder() { OMX_ERRORTYPE result = OMX_ErrorNone; unsigned const int *profile_tbl = (unsigned int const *)mpeg4_profile_level_table; OMX_U32 mb_per_sec, mb_per_frame; bool profile_level_found = false; OMX_U32 eProfile,eLevel; OMX_PARAM_PORTDEFINITIONTYPE portdef; // OMX_IndexParamPortDefinition #ifdef QCOM_EXT OMX_QCOM_PARAM_PORTDEFINITIONTYPE qPortDefnType; #endif portdef.nPortIndex = (OMX_U32) 0; // input result = OMX_GetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portdef); E("\n OMX_IndexParamPortDefinition Get Paramter on input port"); CHK(result); portdef.format.video.nFrameWidth = m_sProfile.nFrameWidth; portdef.format.video.nFrameHeight = m_sProfile.nFrameHeight; E ("\n Height %lu width %lu bit rate %lu",portdef.format.video.nFrameHeight ,portdef.format.video.nFrameWidth,portdef.format.video.nBitrate); result = OMX_SetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portdef); E("\n OMX_IndexParamPortDefinition Set Paramter on input port"); CHK(result); // once more to get proper buffer size result = OMX_GetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portdef); E("\n OMX_IndexParamPortDefinition Get Paramter on input port, 2nd pass"); CHK(result); // update size accordingly m_sProfile.nFrameBytes = portdef.nBufferSize; portdef.nPortIndex = (OMX_U32) 1; // output result = OMX_GetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portdef); E("\n OMX_IndexParamPortDefinition Get Paramter on output port"); CHK(result); portdef.format.video.nFrameWidth = m_sProfile.nFrameWidth; portdef.format.video.nFrameHeight = m_sProfile.nFrameHeight; portdef.format.video.nBitrate = m_sProfile.nBitrate; FractionToQ16(portdef.format.video.xFramerate,(int) (m_sProfile.nFramerate * 2),2); result = OMX_SetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portdef); E("\n OMX_IndexParamPortDefinition Set Paramter on output port"); CHK(result); #ifdef QCOM_EXT qPortDefnType.nPortIndex = PORT_INDEX_IN; qPortDefnType.nMemRegion = OMX_QCOM_MemRegionEBI1; qPortDefnType.nSize = sizeof(OMX_QCOM_PARAM_PORTDEFINITIONTYPE); result = OMX_SetParameter(m_hHandle, (OMX_INDEXTYPE)OMX_QcomIndexPortDefn, &qPortDefnType); #endif if (!m_sProfile.nUserProfile) { // profile not set by user, go ahead with table calculation //validate the ht,width,fps,bitrate and set the appropriate profile and level if (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4) { profile_tbl = (unsigned int const *)mpeg4_profile_level_table; } else if (m_sProfile.eCodec == OMX_VIDEO_CodingAVC) { profile_tbl = (unsigned int const *)h264_profile_level_table; } else if (m_sProfile.eCodec == OMX_VIDEO_CodingH263) { profile_tbl = (unsigned int const *)h263_profile_level_table; } #ifdef _MSM8974_ else if (m_sProfile.eCodec == OMX_VIDEO_CodingVPX) { profile_tbl = (unsigned int const *)VP8_profile_level_table; } #endif mb_per_frame = ((m_sProfile.nFrameHeight+15)>>4)* ((m_sProfile.nFrameWidth+15)>>4); mb_per_sec = mb_per_frame*(m_sProfile.nFramerate); do { if (mb_per_frame <= (unsigned int)profile_tbl[0]) { if (mb_per_sec <= (unsigned int)profile_tbl[1]) { if (m_sProfile.nBitrate <= (unsigned int)profile_tbl[2]) { eLevel = (int)profile_tbl[3]; eProfile = (int)profile_tbl[4]; E("\n profile/level found: %lu/%lu\n",eProfile, eLevel); profile_level_found = true; break; } } } profile_tbl = profile_tbl + 5; } while (profile_tbl[0] != 0); if ( profile_level_found != true ) { E("\n Error: Unsupported profile/level\n"); return OMX_ErrorNone; } } else { // Profile set by user! eProfile = m_sProfile.nUserProfile; eLevel = 0; } if (m_sProfile.eCodec == OMX_VIDEO_CodingH263) { D("Configuring H263..."); OMX_VIDEO_PARAM_H263TYPE h263; result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoH263, &h263); CHK(result); h263.nPortIndex = (OMX_U32) PORT_INDEX_OUT; h263.nPFrames = m_sProfile.nFramerate * 2 - 1; // intra period h263.nBFrames = 0; h263.eProfile = (OMX_VIDEO_H263PROFILETYPE)eProfile; h263.eLevel = (OMX_VIDEO_H263LEVELTYPE)eLevel; h263.bPLUSPTYPEAllowed = OMX_FALSE; h263.nAllowedPictureTypes = 2; h263.bForceRoundingTypeToZero = OMX_TRUE; h263.nPictureHeaderRepetition = 0; h263.nGOBHeaderInterval = 1; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoH263, &h263); } else { D("Configuring MP4/H264..."); OMX_VIDEO_PARAM_PROFILELEVELTYPE profileLevel; // OMX_IndexParamVideoProfileLevelCurrent profileLevel.nPortIndex = (OMX_U32) PORT_INDEX_OUT; profileLevel.eProfile = eProfile; profileLevel.eLevel = eLevel; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoProfileLevelCurrent, &profileLevel); E("\n OMX_IndexParamVideoProfileLevelCurrent Set Paramter port"); CHK(result); //profileLevel.eLevel = (OMX_U32) m_sProfile.eLevel; result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoProfileLevelCurrent, &profileLevel); E("\n OMX_IndexParamVideoProfileLevelCurrent Get Paramter port"); D ("\n Profile = %lu level = %lu",profileLevel.eProfile,profileLevel.eLevel); CHK(result); if (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4) { OMX_VIDEO_PARAM_MPEG4TYPE mp4; // OMX_IndexParamVideoMpeg4 result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoMpeg4, &mp4); CHK(result); mp4.nPortIndex = (OMX_U32) PORT_INDEX_OUT; mp4.nTimeIncRes = 1000; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoMpeg4, &mp4); CHK(result); } } if (m_sProfile.eCodec == OMX_VIDEO_CodingAVC) { #if 1 /////////////C A B A C ///A N D/////D E B L O C K I N G ///////////////// OMX_VIDEO_PARAM_AVCTYPE avcdata; avcdata.nPortIndex = (OMX_U32)PORT_INDEX_OUT; result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoAvc, &avcdata); CHK(result); // TEST VALUES (CHANGE FOR DIFF CONFIG's) avcdata.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; // avcdata.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterDisable; // avcdata.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterDisableSliceBoundary; avcdata.bEntropyCodingCABAC = OMX_FALSE; // avcdata.bEntropyCodingCABAC = OMX_TRUE; avcdata.nCabacInitIdc = 1; /////////////////////////////////////////////// result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoAvc, &avcdata); CHK(result); /////////////C A B A C ///A N D/////D E B L O C K I N G ///////////////// #endif } OMX_VIDEO_PARAM_BITRATETYPE bitrate; // OMX_IndexParamVideoBitrate bitrate.nPortIndex = (OMX_U32)PORT_INDEX_OUT; result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoBitrate, &bitrate); E("\n OMX_IndexParamVideoBitrate Get Paramter port"); CHK(result); bitrate.eControlRate = m_sProfile.eControlRate; bitrate.nTargetBitrate = m_sProfile.nBitrate; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoBitrate, &bitrate); E("\n OMX_IndexParamVideoBitrate Set Paramter port"); CHK(result); OMX_VIDEO_PARAM_PORTFORMATTYPE framerate; // OMX_IndexParamVidePortFormat framerate.nPortIndex = 0; result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoPortFormat, &framerate); E("\n OMX_IndexParamVideoPortFormat Get Paramter port"); CHK(result); FractionToQ16(framerate.xFramerate,(int) (m_sProfile.nFramerate * 2),2); result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoPortFormat, &framerate); E("\n OMX_IndexParamVideoPortFormat Set Paramter port"); CHK(result); #if 1 ///////////////////I N T R A P E R I O D /////////////////// QOMX_VIDEO_INTRAPERIODTYPE intra; intra.nPortIndex = (OMX_U32) PORT_INDEX_OUT; // output result = OMX_GetConfig(m_hHandle, (OMX_INDEXTYPE) QOMX_IndexConfigVideoIntraperiod, (OMX_PTR) &intra); if (result == OMX_ErrorNone) { intra.nPFrames = (OMX_U32) (2 * m_sProfile.nFramerate - 1); //setting I //frame interval to //2 x framerate intra.nIDRPeriod = 1; //every I frame is an IDR intra.nPortIndex = (OMX_U32) PORT_INDEX_OUT; result = OMX_SetConfig(m_hHandle, (OMX_INDEXTYPE) QOMX_IndexConfigVideoIntraperiod, (OMX_PTR) &intra); } else { E("failed to get state", 0, 0, 0); } ///////////////////I N T R A P E R I O D /////////////////// #endif #if 1 ///////////////////E R R O R C O R R E C T I O N /////////////////// ResyncMarkerType eResyncMarkerType = RESYNC_MARKER_NONE; unsigned long int nResyncMarkerSpacing = 0; OMX_BOOL enableHEC = OMX_FALSE; //For Testing ONLY if (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4) { // MPEG4 // eResyncMarkerType = RESYNC_MARKER_BYTE; // nResyncMarkerSpacing = 1920; eResyncMarkerType = RESYNC_MARKER_MB; nResyncMarkerSpacing = 50; enableHEC = OMX_TRUE; } else if (m_sProfile.eCodec == OMX_VIDEO_CodingH263) { //H263 //eResyncMarkerType = RESYNC_MARKER_GOB; eResyncMarkerType = RESYNC_MARKER_NONE; nResyncMarkerSpacing = 0; } else if (m_sProfile.eCodec == OMX_VIDEO_CodingAVC) { //H264 // eResyncMarkerType = RESYNC_MARKER_BYTE; // nResyncMarkerSpacing = 1920; //nResyncMarkerSpacing sets the slice size in venc_set_multislice_cfg // //As of 9/24/10, it is known that the firmware has a bitstream //corruption issue when RateControl and multislice are enabled for 720P //So, disabling multislice for 720P when ratecontrol is enabled until //the firmware issue is resolved. if ( ( (m_sProfile.nFrameWidth == 1280) && (m_sProfile.nFrameHeight = 720) ) && (m_sProfile.eControlRate != OMX_Video_ControlRateDisable) ) { eResyncMarkerType = RESYNC_MARKER_NONE; nResyncMarkerSpacing = 0; } else { eResyncMarkerType = RESYNC_MARKER_NONE; nResyncMarkerSpacing = 0; } } OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrection; //OMX_IndexParamVideoErrorCorrection errorCorrection.nPortIndex = (OMX_U32) PORT_INDEX_OUT; // output result = OMX_GetParameter(m_hHandle, (OMX_INDEXTYPE) OMX_IndexParamVideoErrorCorrection, (OMX_PTR) &errorCorrection); errorCorrection.bEnableRVLC = OMX_FALSE; errorCorrection.bEnableDataPartitioning = OMX_FALSE; if ((eResyncMarkerType == RESYNC_MARKER_BYTE) && (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4)) { errorCorrection.bEnableResync = OMX_TRUE; errorCorrection.nResynchMarkerSpacing = nResyncMarkerSpacing; errorCorrection.bEnableHEC = enableHEC; } else if ((eResyncMarkerType == RESYNC_MARKER_BYTE) && (m_sProfile.eCodec == OMX_VIDEO_CodingAVC)) { errorCorrection.bEnableResync = OMX_TRUE; errorCorrection.nResynchMarkerSpacing = nResyncMarkerSpacing; } else if ((eResyncMarkerType == RESYNC_MARKER_GOB) && (m_sProfile.eCodec == OMX_VIDEO_CodingH263)) { errorCorrection.bEnableResync = OMX_FALSE; errorCorrection.nResynchMarkerSpacing = nResyncMarkerSpacing; errorCorrection.bEnableDataPartitioning = OMX_TRUE; } result = OMX_SetParameter(m_hHandle, (OMX_INDEXTYPE) OMX_IndexParamVideoErrorCorrection, (OMX_PTR) &errorCorrection); CHK(result); if (eResyncMarkerType == RESYNC_MARKER_MB) { if (m_sProfile.eCodec == OMX_VIDEO_CodingAVC) { OMX_VIDEO_PARAM_AVCTYPE avcdata; avcdata.nPortIndex = (OMX_U32) PORT_INDEX_OUT; // output result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoAvc, (OMX_PTR) &avcdata); CHK(result); if (result == OMX_ErrorNone) { avcdata.nSliceHeaderSpacing = nResyncMarkerSpacing; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoAvc, (OMX_PTR) &avcdata); CHK(result); } } else if (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4) { OMX_VIDEO_PARAM_MPEG4TYPE mp4; mp4.nPortIndex = (OMX_U32) PORT_INDEX_OUT; // output result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoMpeg4, (OMX_PTR) &mp4); CHK(result); if (result == OMX_ErrorNone) { mp4.nSliceHeaderSpacing = nResyncMarkerSpacing; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoMpeg4, (OMX_PTR) &mp4); CHK(result); } } } ///////////////////E R R O R C O R R E C T I O N /////////////////// #endif #if 1 ///////////////////I N T R A R E F R E S H/////////////////// bool bEnableIntraRefresh = OMX_TRUE; if (result == OMX_ErrorNone) { OMX_VIDEO_PARAM_INTRAREFRESHTYPE ir; // OMX_IndexParamVideoIntraRefresh ir.nPortIndex = (OMX_U32) PORT_INDEX_OUT; // output result = OMX_GetParameter(m_hHandle, OMX_IndexParamVideoIntraRefresh, (OMX_PTR) &ir); if (result == OMX_ErrorNone) { if (bEnableIntraRefresh) { ir.eRefreshMode = OMX_VIDEO_IntraRefreshCyclic; ir.nCirMBs = 5; result = OMX_SetParameter(m_hHandle, OMX_IndexParamVideoIntraRefresh, (OMX_PTR) &ir); CHK(result); } } } #endif #if 1 ///////////////////FRAMEPACKING DATA/////////////////// OMX_QCOM_FRAME_PACK_ARRANGEMENT framePackingArrangement; FILE *m_pConfigFile; char m_configFilename [128] = "/data/configFile.cfg"; memset(&framePackingArrangement, 0, sizeof(framePackingArrangement)); m_pConfigFile = fopen(m_configFilename, "r"); if (m_pConfigFile != NULL) { //read all frame packing data framePackingArrangement.nPortIndex = (OMX_U32)PORT_INDEX_OUT; int totalSizeToRead = FRAME_PACK_SIZE * sizeof(OMX_U32); char *pFramePack = (char *) &(framePackingArrangement.id); while ( ( (fscanf(m_pConfigFile, "%d", pFramePack)) != EOF ) && (totalSizeToRead != 0) ) { //printf("Addr = %p, Value read = %d, sizeToRead remaining=%d\n", // pFramePack, *pFramePack, totalSizeToRead); pFramePack += sizeof(OMX_U32); totalSizeToRead -= sizeof(OMX_U32); } //close the file. fclose(m_pConfigFile); printf("Frame Packing data from config file:\n"); PrintFramePackArrangement(framePackingArrangement); } else { D("\n Config file does not exist or could not be opened."); //set the default values framePackingArrangement.nPortIndex = (OMX_U32)PORT_INDEX_OUT; framePackingArrangement.id = 123; framePackingArrangement.cancel_flag = false; framePackingArrangement.type = 3; framePackingArrangement.quincunx_sampling_flag = false; framePackingArrangement.content_interpretation_type = 0; framePackingArrangement.spatial_flipping_flag = true; framePackingArrangement.frame0_flipped_flag = false; framePackingArrangement.field_views_flag = false; framePackingArrangement.current_frame_is_frame0_flag = false; framePackingArrangement.frame0_self_contained_flag = true; framePackingArrangement.frame1_self_contained_flag = false; framePackingArrangement.frame0_grid_position_x = 3; framePackingArrangement.frame0_grid_position_y = 15; framePackingArrangement.frame1_grid_position_x = 11; framePackingArrangement.frame1_grid_position_y = 7; framePackingArrangement.reserved_byte = 0; framePackingArrangement.repetition_period = 16381; framePackingArrangement.extension_flag = false; printf("Frame Packing Defaults :\n"); PrintFramePackArrangement(framePackingArrangement); } result = OMX_SetConfig(m_hHandle, (OMX_INDEXTYPE)OMX_QcomIndexConfigVideoFramePackingArrangement, (OMX_PTR) &framePackingArrangement); CHK(result); //////////////////////OMX_VIDEO_PARAM_INTRAREFRESHTYPE/////////////////// #endif OMX_CONFIG_FRAMERATETYPE enc_framerate; // OMX_IndexConfigVideoFramerate enc_framerate.nPortIndex = (OMX_U32)PORT_INDEX_OUT; result = OMX_GetConfig(m_hHandle, OMX_IndexConfigVideoFramerate, &enc_framerate); CHK(result); FractionToQ16(enc_framerate.xEncodeFramerate,(int) (m_sProfile.nFramerate * 2),2); result = OMX_SetConfig(m_hHandle, OMX_IndexConfigVideoFramerate, &enc_framerate); CHK(result); return OMX_ErrorNone; } //////////////////////////////////////////////////////////////////////////////// void SendMessage(MsgId id, MsgData* data) { pthread_mutex_lock(&m_mutex); if (m_sMsgQ.size >= MAX_MSG) { E("main msg m_sMsgQ is full"); return; } m_sMsgQ.q[(m_sMsgQ.head + m_sMsgQ.size) % MAX_MSG].id = id; if (data) m_sMsgQ.q[(m_sMsgQ.head + m_sMsgQ.size) % MAX_MSG].data = *data; ++m_sMsgQ.size; pthread_cond_signal(&m_signal); pthread_mutex_unlock(&m_mutex); } //////////////////////////////////////////////////////////////////////////////// void PopMessage(Msg* msg) { pthread_mutex_lock(&m_mutex); while (m_sMsgQ.size == 0) { pthread_cond_wait(&m_signal, &m_mutex); } *msg = m_sMsgQ.q[m_sMsgQ.head]; --m_sMsgQ.size; m_sMsgQ.head = (m_sMsgQ.head + 1) % MAX_MSG; pthread_mutex_unlock(&m_mutex); } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE EVT_CB(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) { #define SET_STATE(eState) \ case eState: \ { \ D("" # eState " complete"); \ m_eState = eState; \ break; \ } if (eEvent == OMX_EventCmdComplete) { if ((OMX_COMMANDTYPE) nData1 == OMX_CommandStateSet) { switch ((OMX_STATETYPE) nData2) { SET_STATE(OMX_StateLoaded); SET_STATE(OMX_StateIdle); SET_STATE(OMX_StateExecuting); SET_STATE(OMX_StateInvalid); SET_STATE(OMX_StateWaitForResources); SET_STATE(OMX_StatePause); default: E("invalid state %d", (int) nData2); } } } else if (eEvent == OMX_EventError) { E("OMX_EventError"); } else { E("unexpected event %d", (int) eEvent); } return OMX_ErrorNone; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE EBD_CB(OMX_IN OMX_HANDLETYPE hComponent, OMX_IN OMX_PTR pAppData, OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) { D("Got EBD callback ts=%lld", pBuffer->nTimeStamp); for (int i = 0; i < num_in_buffers; i++) { // mark this buffer ready for use again if (m_pInBuffers[i] == pBuffer) { D("Marked input buffer idx %d as free, buf %p", i, pBuffer->pBuffer); m_bInFrameFree[i] = OMX_TRUE; break; } } if (m_eMode == MODE_LIVE_ENCODE) { CameraTest_ReleaseFrame(pBuffer->pBuffer, ((OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO*)pBuffer->pAppPrivate)); } else { // wake up main thread and tell it to send next frame MsgData data; data.sBitstreamData.pBuffer = pBuffer; SendMessage(MSG_ID_INPUT_FRAME_DONE, &data); } return OMX_ErrorNone; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE FBD_CB(OMX_OUT OMX_HANDLETYPE hComponent, OMX_OUT OMX_PTR pAppData, OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) { D("Got FBD callback ts=%lld", pBuffer->nTimeStamp); static long long prevTime = 0; long long currTime = GetTimeStamp(); m_bWatchDogKicked = true; /* Empty Buffers should not be counted */ if (pBuffer->nFilledLen !=0) { /* Counting Buffers supplied from OpneMax Encoder */ fbd_cnt++; tot_bufsize += pBuffer->nFilledLen; } if (prevTime != 0) { long long currTime = GetTimeStamp(); D("FBD_DELTA = %lld\n", currTime - prevTime); } prevTime = currTime; if (m_eMode == MODE_PROFILE) { // if we are profiling we are not doing file I/O // so just give back to encoder if (OMX_FillThisBuffer(m_hHandle, pBuffer) != OMX_ErrorNone) { E("empty buffer failed for profiling"); } } else { // wake up main thread and tell it to write to file MsgData data; data.sBitstreamData.pBuffer = pBuffer; SendMessage(MSG_ID_OUTPUT_FRAME_DONE, &data); } return OMX_ErrorNone; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE VencTest_Initialize() { OMX_ERRORTYPE result = OMX_ErrorNone; static OMX_CALLBACKTYPE sCallbacks = {EVT_CB, EBD_CB, FBD_CB}; int i; for (i = 0; i < num_in_buffers; i++) { m_pInBuffers[i] = NULL; } result = OMX_Init(); CHK(result); if (m_sProfile.eCodec == OMX_VIDEO_CodingMPEG4) { result = OMX_GetHandle(&m_hHandle, "OMX.qcom.video.encoder.mpeg4", NULL, &sCallbacks); // CHK(result); } else if (m_sProfile.eCodec == OMX_VIDEO_CodingH263) { result = OMX_GetHandle(&m_hHandle, "OMX.qcom.video.encoder.h263", NULL, &sCallbacks); CHK(result); } #ifdef _MSM8974_ else if (m_sProfile.eCodec == OMX_VIDEO_CodingVPX) { result = OMX_GetHandle(&m_hHandle, "OMX.qcom.video.encoder.vp8", NULL, &sCallbacks); CHK(result); } #endif else { result = OMX_GetHandle(&m_hHandle, "OMX.qcom.video.encoder.avc", NULL, &sCallbacks); CHK(result); } result = ConfigureEncoder(); CHK(result); return result; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE VencTest_RegisterYUVBuffer(OMX_BUFFERHEADERTYPE** ppBufferHeader, OMX_U8 *pBuffer, OMX_PTR pAppPrivate) { OMX_ERRORTYPE result = OMX_ErrorNone; #if 0 D("register buffer"); if ((result = OMX_AllocateBuffer(m_hHandle, ppBufferHeader, (OMX_U32) PORT_INDEX_IN, pAppPrivate, m_sProfile.nFrameBytes )) != OMX_ErrorNone) { E("use buffer failed"); } else { E("Allocate Buffer Success %x", (*ppBufferHeader)->pBuffer); } #endif D("register buffer"); D("Calling UseBuffer for Input port"); if ((result = OMX_UseBuffer(m_hHandle, ppBufferHeader, (OMX_U32) PORT_INDEX_IN, pAppPrivate, m_sProfile.nFrameBytes, pBuffer)) != OMX_ErrorNone) { E("use buffer failed"); } return result; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE VencTest_EncodeFrame(void* pYUVBuff, long long nTimeStamp) { OMX_ERRORTYPE result = OMX_ErrorUndefined; D("calling OMX empty this buffer"); for (int i = 0; i < num_in_buffers; i++) { if (pYUVBuff == m_pInBuffers[i]->pBuffer) { m_pInBuffers[i]->nTimeStamp = nTimeStamp; D("Sending Buffer - %x", m_pInBuffers[i]->pBuffer); result = OMX_EmptyThisBuffer(m_hHandle, m_pInBuffers[i]); /* Counting Buffers supplied to OpenMax Encoder */ if (OMX_ErrorNone == result) ebd_cnt++; CHK(result); break; } } return result; } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE VencTest_Exit(void) { int i; OMX_ERRORTYPE result = OMX_ErrorNone; D("trying to exit venc"); D("going to idle state"); SetState(OMX_StateIdle); D("going to loaded state"); //SetState(OMX_StateLoaded); OMX_SendCommand(m_hHandle, OMX_CommandStateSet, (OMX_U32) OMX_StateLoaded, NULL); for (i = 0; i < num_in_buffers; i++) { D("free buffer"); if (m_pInBuffers[i]->pBuffer) { // free(m_pInBuffers[i]->pBuffer); result = OMX_FreeBuffer(m_hHandle, PORT_INDEX_IN, m_pInBuffers[i]); CHK(result); } else { E("buffer %d is null", i); result = OMX_ErrorUndefined; CHK(result); } } for (i = 0; i < num_out_buffers; i++) { D("free buffer"); if (m_pOutBuffers[i]->pBuffer) { free(m_pOutBuffers[i]->pBuffer); result = OMX_FreeBuffer(m_hHandle, PORT_INDEX_OUT, m_pOutBuffers[i]); CHK(result); } else { E("buffer %d is null", i); result = OMX_ErrorUndefined; CHK(result); } } while (m_eState != OMX_StateLoaded) { sleep(1); } D("component_deinit..."); result = OMX_Deinit(); CHK(result); D("venc is exiting..."); return result; } //////////////////////////////////////////////////////////////////////////////// void VencTest_ReadDynamicConfigMsg() { char frame_n[8], config[16], param[8]; char *dest = frame_n; bool end = false; int cntr, nparam = 0; memset(&dynamic_config, 0, sizeof(struct DynamicConfig)); do { cntr = -1; do { dest[++cntr] = fgetc(m_pDynConfFile); } while (dest[cntr] != ' ' && dest[cntr] != '\t' && dest[cntr] != '\n' && dest[cntr] != '\r' && !feof(m_pDynConfFile)); if (dest[cntr] == '\n' || dest[cntr] == '\r') end = true; dest[cntr] = NULL; if (dest == frame_n) dest = config; else if (dest == config) dest = param; else end = true; nparam++; } while (!end && !feof(m_pDynConfFile)); if (nparam > 1) { dynamic_config.pending = true; dynamic_config.frame_num = atoi(frame_n); if (!strcmp(config, "bitrate")) { dynamic_config.config_param = OMX_IndexConfigVideoBitrate; dynamic_config.config_data.bitrate.nPortIndex = PORT_INDEX_OUT; dynamic_config.config_data.bitrate.nEncodeBitrate = strtoul(param, NULL, 10); } else if (!strcmp(config, "framerate")) { dynamic_config.config_param = OMX_IndexConfigVideoFramerate; dynamic_config.config_data.framerate.nPortIndex = PORT_INDEX_OUT; dynamic_config.config_data.f_framerate = atof(param); } else if (!strcmp(config, "iperiod")) { dynamic_config.config_param = (OMX_INDEXTYPE)QOMX_IndexConfigVideoIntraperiod; dynamic_config.config_data.intraperiod.nPortIndex = PORT_INDEX_OUT; dynamic_config.config_data.intraperiod.nPFrames = strtoul(param, NULL, 10) - 1; dynamic_config.config_data.intraperiod.nIDRPeriod = 1; // This value is ignored in OMX component } else if (!strcmp(config, "ivoprefresh")) { dynamic_config.config_param = OMX_IndexConfigVideoIntraVOPRefresh; dynamic_config.config_data.intravoprefresh.nPortIndex = PORT_INDEX_OUT; dynamic_config.config_data.intravoprefresh.IntraRefreshVOP = OMX_TRUE; } else if (!strcmp(config, "rotation")) { dynamic_config.config_param = OMX_IndexConfigCommonRotate; dynamic_config.config_data.rotation.nPortIndex = PORT_INDEX_OUT; dynamic_config.config_data.rotation.nRotation = strtoul(param, NULL, 10); } else { E("UNKNOWN CONFIG PARAMETER: %s!", config); dynamic_config.pending = false; } } else if (feof(m_pDynConfFile)) { fclose(m_pDynConfFile); m_pDynConfFile = NULL; } } void VencTest_ProcessDynamicConfigurationFile() { do { if (dynamic_config.pending) { if (m_nFrameIn == dynamic_config.frame_num) { if (dynamic_config.config_param == OMX_IndexConfigVideoFramerate) { m_sProfile.nFramerate = dynamic_config.config_data.f_framerate; FractionToQ16(dynamic_config.config_data.framerate.xEncodeFramerate, (int)(m_sProfile.nFramerate * 2), 2); } if (OMX_SetConfig(m_hHandle, dynamic_config.config_param, &dynamic_config.config_data) != OMX_ErrorNone) E("ERROR: Setting dynamic config to OMX param[0x%x]", dynamic_config.config_param); dynamic_config.pending = false; } else if (m_nFrameIn > dynamic_config.frame_num) { E("WARNING: Config change requested in passed frame(%d)", dynamic_config.frame_num); dynamic_config.pending = false; } } if (!dynamic_config.pending) VencTest_ReadDynamicConfigMsg(); } while (!dynamic_config.pending && m_pDynConfFile); } //////////////////////////////////////////////////////////////////////////////// OMX_ERRORTYPE VencTest_ReadAndEmpty(OMX_BUFFERHEADERTYPE* pYUVBuffer) { OMX_ERRORTYPE result = OMX_ErrorNone; #ifdef T_ARM #if defined(MAX_RES_720P) && !defined(_MSM8974_) if (read(m_nInFd, pYUVBuffer->pBuffer, m_sProfile.nFrameBytes) != m_sProfile.nFrameBytes) { return OMX_ErrorUndefined; } #elif _MSM8974_ int i, lscanl, lstride, cscanl, cstride, height, width; int bytes = 0, read_bytes = 0; OMX_U8 *yuv = pYUVBuffer->pBuffer; height = m_sProfile.nFrameHeight; width = m_sProfile.nFrameWidth; lstride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width); lscanl = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height); cstride = VENUS_UV_STRIDE(COLOR_FMT_NV12, width); cscanl = VENUS_UV_SCANLINES(COLOR_FMT_NV12, height); for (i = 0; i < height; i++) { bytes = read(m_nInFd, yuv, width); if (bytes != width) { E("read failed: %d != %d\n", read, width); return OMX_ErrorUndefined; } read_bytes += bytes; yuv += lstride; } yuv = pYUVBuffer->pBuffer + (lscanl * lstride); for (i = 0; i < ((height + 1) >> 1); i++) { bytes = read(m_nInFd, yuv, width); if (bytes != width) { E("read failed: %d != %d\n", read, width); return OMX_ErrorUndefined; } read_bytes += bytes; yuv += cstride; } m_sProfile.nFrameRead = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height); E("\n\nActual read bytes: %d, NV12 buffer size: %d\n\n\n", read_bytes, m_sProfile.nFrameRead); #else OMX_U32 bytestoread = m_sProfile.nFrameWidth*m_sProfile.nFrameHeight; // read Y first if (read(m_nInFd, pYUVBuffer->pBuffer, bytestoread) != bytestoread) return OMX_ErrorUndefined; // check alignment for offset to C OMX_U32 offset_to_c = m_sProfile.nFrameWidth * m_sProfile.nFrameHeight; const OMX_U32 C_2K = (1024*2), MASK_2K = C_2K-1, IMASK_2K = ~MASK_2K; if (offset_to_c & MASK_2K) { // offset to C is not 2k aligned, adjustment is required offset_to_c = (offset_to_c & IMASK_2K) + C_2K; } bytestoread = m_sProfile.nFrameWidth*m_sProfile.nFrameHeight/2; // read C if (read(m_nInFd, pYUVBuffer->pBuffer + offset_to_c, bytestoread)!= bytestoread) return OMX_ErrorUndefined; #endif #else { char * pInputbuf = (char *)(pYUVBuffer->pBuffer) ; read(m_nInFd,pInputbuf,m_sProfile.nFrameBytes) ; } #endif if (m_pDynConfFile) VencTest_ProcessDynamicConfigurationFile(); D("about to call VencTest_EncodeFrame..."); pthread_mutex_lock(&m_mutex); ++m_nFrameIn; #ifdef _MSM8974_ pYUVBuffer->nFilledLen = m_sProfile.nFrameRead; #else pYUVBuffer->nFilledLen = m_sProfile.nFrameBytes; #endif D("Called Buffer with Data filled length %d",pYUVBuffer->nFilledLen); result = VencTest_EncodeFrame(pYUVBuffer->pBuffer, m_nTimeStamp); m_nTimeStamp += (1000000) / m_sProfile.nFramerate; CHK(result); pthread_mutex_unlock(&m_mutex); return result; } //////////////////////////////////////////////////////////////////////////////// void PreviewCallback(int nFD, int nOffset, void* pPhys, void* pVirt, long long nTimeStamp) { D("================= preview frame %d, phys=0x%x, nTimeStamp(millis)=%lld", m_nFrameIn+1, pPhys, (nTimeStamp / 1000)); if (m_nFrameIn == m_nFramePlay && m_nFramePlay != 0) { // we will stop camera after last frame is encoded. // for now just ignore input frames CameraTest_ReleaseFrame(pPhys, pVirt); return; } // see if we should stop pthread_mutex_lock(&m_mutex); ++m_nFrameIn; pthread_mutex_unlock(&m_mutex); if (m_eMode == MODE_LIVE_ENCODE) { OMX_ERRORTYPE result; // register new camera buffers with encoder int i; for (i = 0; i < num_in_buffers; i++) { if (m_pInBuffers[i] != NULL && m_pInBuffers[i]->pBuffer == pPhys) { break; } else if (m_pInBuffers[i] == NULL) { D("registering buffer..."); result = VencTest_RegisterYUVBuffer(&m_pInBuffers[i], (OMX_U8*) pPhys, (OMX_PTR) pVirt); // store virt in app private field D("register done"); CHK(result); break; } } if (i == num_in_buffers) { E("There are more camera buffers than we thought"); CHK(1); } // encode the yuv frame D("StartEncodeTime=%lld", GetTimeStamp()); result = VencTest_EncodeFrame(pPhys, nTimeStamp); CHK(result); // FBTest_DisplayImage(nFD, nOffset); } else { // FBTest_DisplayImage(nFD, nOffset); CameraTest_ReleaseFrame(pPhys, pVirt); } } //////////////////////////////////////////////////////////////////////////////// void usage(char* filename) { char* fname = strrchr(filename, (int) '/'); fname = (fname == NULL) ? filename : fname; fprintf(stderr, "usage: %s LIVE <QCIF|QVGA> <MP4|H263> <FPS> <BITRATE> <NFRAMES> <OUTFILE>\n", fname); fprintf(stderr, "usage: %s FILE <QCIF|QVGA> <MP4|H263 <FPS> <BITRATE> <NFRAMES> <INFILE> <OUTFILE> ", fname); fprintf(stderr, "<Dynamic config file - opt> <Rate Control - opt> <AVC Slice Mode - opt>\n", fname); fprintf(stderr, "usage: %s PROFILE <QCIF|QVGA> <MP4|H263 <FPS> <BITRATE> <NFRAMES> <INFILE>\n", fname); fprintf(stderr, "usage: %s PREVIEW <QCIF|QVGA> <FPS> <NFRAMES>\n", fname); fprintf(stderr, "usage: %s DISPLAY <QCIF|QVGA> <FPS> <NFRAMES> <INFILE>\n", fname); fprintf(stderr, "\n BITRATE - bitrate in kbps\n"); fprintf(stderr, " FPS - frames per second\n"); fprintf(stderr, " NFRAMES - number of frames to play, 0 for infinite\n"); fprintf(stderr, " RateControl (Values 0 - 4 for RC_OFF, RC_CBR_CFR, RC_CBR_VFR, RC_VBR_CFR, RC_VBR_VFR\n"); exit(1); } bool parseWxH(char *str, OMX_U32 *width, OMX_U32 *height) { bool parseOK = false; const char delimiters[] = " x*,"; char *token, *dupstr, *temp; OMX_U32 w, h; dupstr = strdup(str); token = strtok_r(dupstr, delimiters, &temp); if (token) { w = strtoul(token, NULL, 10); token = strtok_r(NULL, delimiters, &temp); if (token) { h = strtoul(token, NULL, 10); if (w != ULONG_MAX && h != ULONG_MAX) { #ifdef MAX_RES_720P if ((w * h >> 8) <= 3600) { parseOK = true; *width = w; *height = h; } #else if ((w * h >> 8) <= 8160) { parseOK = true; *width = w; *height = h; } #endif else E("\nInvalid dimensions %dx%d",w,h); } } } free(dupstr); return parseOK; } //////////////////////////////////////////////////////////////////////////////// void parseArgs(int argc, char** argv) { int dyn_file_arg = argc; if (argc == 1) { usage(argv[0]); } else if (strcmp("PREVIEW", argv[1]) == 0 || strcmp("preview", argv[1]) == 0) { m_eMode = MODE_PREVIEW; if (argc != 5) { usage(argv[0]); } } else if (strcmp("DISPLAY", argv[1]) == 0 || strcmp("display", argv[1]) == 0) { m_eMode = MODE_DISPLAY; if (argc != 6) { usage(argv[0]); } m_sProfile.cInFileName = argv[5]; m_sProfile.cOutFileName = NULL; } else if (strcmp("LIVE", argv[1]) == 0 || strcmp("live", argv[1]) == 0) {//263 m_eMode = MODE_LIVE_ENCODE; if (argc != 8) { usage(argv[0]); } m_sProfile.cInFileName = NULL; m_sProfile.cOutFileName = argv[7]; } else if (strcmp("FILE", argv[1]) == 0 || strcmp("file", argv[1]) == 0) {//263 m_eMode = MODE_FILE_ENCODE; if (argc < 9 || argc > 13) { usage(argv[0]); } else { if (argc > 9) dyn_file_arg = 9; if (argc > 10) { m_sProfile.eControlRate = OMX_Video_ControlRateVariable; int RC = atoi(argv[10]); switch (RC) { case 0: m_sProfile.eControlRate = OMX_Video_ControlRateDisable ;//VENC_RC_NONE break; case 1: m_sProfile.eControlRate = OMX_Video_ControlRateConstant;//VENC_RC_CBR_CFR break; case 2: m_sProfile.eControlRate = OMX_Video_ControlRateConstantSkipFrames;//VENC_RC_CBR_VFR break; case 3: m_sProfile.eControlRate =OMX_Video_ControlRateVariable ;//VENC_RC_VBR_CFR break; case 4: m_sProfile.eControlRate = OMX_Video_ControlRateVariableSkipFrames;//VENC_RC_VBR_VFR break; default: E("invalid rate control selection"); m_sProfile.eControlRate = OMX_Video_ControlRateVariable; //VENC_RC_VBR_CFR break; } } if (argc > 11) { int profile_argi = 11; if (!strcmp(argv[3], "H264") || !strcmp(argv[3], "h264")) { profile_argi = 12; D("\nSetting AVCSliceMode ... "); int AVCSliceMode = atoi(argv[11]); switch (AVCSliceMode) { case 0: m_sProfile.eSliceMode = OMX_VIDEO_SLICEMODE_AVCDefault; break; case 1: m_sProfile.eSliceMode = OMX_VIDEO_SLICEMODE_AVCMBSlice; break; case 2: m_sProfile.eSliceMode = OMX_VIDEO_SLICEMODE_AVCByteSlice; break; default: E("invalid Slice Mode"); m_sProfile.eSliceMode = OMX_VIDEO_SLICEMODE_AVCDefault; break; } } if (profile_argi < argc) { if (!strncmp(argv[profile_argi], "0x", 2) || !strncmp(argv[profile_argi], "0x", 2)) { m_sProfile.nUserProfile = strtoul(argv[profile_argi], NULL, 16); } else { m_sProfile.nUserProfile = strtoul(argv[profile_argi], NULL, 10); } if (!m_sProfile.nUserProfile || m_sProfile.nUserProfile == ULONG_MAX) { E("invalid specified Profile %s, using default", argv[profile_argi]); m_sProfile.nUserProfile = 0; } } } } m_sProfile.cInFileName = argv[7]; m_sProfile.cOutFileName = argv[8]; } else if (strcmp("PROFILE", argv[1]) == 0 || strcmp("profile", argv[1]) == 0) {//263 m_eMode = MODE_PROFILE; if (argc != 8) { usage(argv[0]); } m_sProfile.cInFileName = argv[7]; m_sProfile.cOutFileName = NULL; } else { usage(argv[0]); } if (strcmp("QCIF", argv[2]) == 0 || strcmp("qcif", argv[2]) == 0) { m_sProfile.nFrameWidth = 176; m_sProfile.nFrameHeight = 144; m_sProfile.nFrameBytes = 176*144*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level0; } else if (strcmp("QVGA", argv[2]) == 0 || strcmp("qvga", argv[2]) == 0) { m_sProfile.nFrameWidth = 320; m_sProfile.nFrameHeight = 240; m_sProfile.nFrameBytes = 320*240*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("VGA", argv[2]) == 0 || strcmp("vga", argv[2]) == 0) { m_sProfile.nFrameWidth = 640; m_sProfile.nFrameHeight = 480; m_sProfile.nFrameBytes = 640*480*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("WVGA", argv[2]) == 0 || strcmp("wvga", argv[2]) == 0) { m_sProfile.nFrameWidth = 800; m_sProfile.nFrameHeight = 480; m_sProfile.nFrameBytes = 800*480*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("CIF", argv[2]) == 0 || strcmp("cif", argv[2]) == 0) { m_sProfile.nFrameWidth = 352; m_sProfile.nFrameHeight = 288; m_sProfile.nFrameBytes = 352*288*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("720", argv[2]) == 0) { m_sProfile.nFrameWidth = 1280; m_sProfile.nFrameHeight = 720; m_sProfile.nFrameBytes = 720*1280*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("1080", argv[2]) == 0) { m_sProfile.nFrameWidth = 1920; m_sProfile.nFrameHeight = 1080; m_sProfile.nFrameBytes = 1920*1080*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } #ifdef _MSM8974_ else if (strcmp("4K2K", argv[2]) == 0) { m_sProfile.nFrameWidth = 4096; m_sProfile.nFrameHeight = 2160; m_sProfile.nFrameBytes = 4096*2160*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else if (strcmp("2160P", argv[2]) == 0) { m_sProfile.nFrameWidth = 3840; m_sProfile.nFrameHeight = 2160; m_sProfile.nFrameBytes = 3840*2160*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } #endif else if (parseWxH(argv[2], &m_sProfile.nFrameWidth, &m_sProfile.nFrameHeight)) { m_sProfile.nFrameBytes = m_sProfile.nFrameWidth*m_sProfile.nFrameHeight*3/2; m_sProfile.eLevel = OMX_VIDEO_MPEG4Level1; } else { usage(argv[0]); } #ifdef _MSM8974_ m_sProfile.nFramestride = (m_sProfile.nFrameWidth + 31) & (~31); m_sProfile.nFrameScanlines = (m_sProfile.nFrameHeight + 31) & (~31); m_sProfile.nFrameBytes = ((m_sProfile.nFramestride * m_sProfile.nFrameScanlines * 3/2) + 4095) & (~4095); m_sProfile.nFrameRead = m_sProfile.nFramestride * m_sProfile.nFrameScanlines * 3/2; #endif if (m_eMode == MODE_DISPLAY || m_eMode == MODE_PREVIEW) { m_sProfile.nFramerate = atof(argv[3]); m_nFramePlay = atoi(argv[4]); } else if (m_eMode == MODE_LIVE_ENCODE || m_eMode == MODE_FILE_ENCODE || m_eMode == MODE_PROFILE) { if ((!strcmp(argv[3], "MP4")) || (!strcmp(argv[3], "mp4"))) { m_sProfile.eCodec = OMX_VIDEO_CodingMPEG4; } else if ((!strcmp(argv[3], "H263")) || (!strcmp(argv[3], "h263"))) { m_sProfile.eCodec = OMX_VIDEO_CodingH263; } else if ((!strcmp(argv[3], "H264")) || (!strcmp(argv[3], "h264"))) { m_sProfile.eCodec = OMX_VIDEO_CodingAVC; } #ifdef _MSM8974_ else if ((!strcmp(argv[3], "VP8")) || (!strcmp(argv[3], "vp8"))) { m_sProfile.eCodec = OMX_VIDEO_CodingVPX; } #endif else { usage(argv[0]); } m_sProfile.nFramerate = atof(argv[4]); m_sProfile.nBitrate = atoi(argv[5]); // m_sProfile.eControlRate = OMX_Video_ControlRateVariable; m_nFramePlay = atoi(argv[6]); if (dyn_file_arg < argc) { m_pDynConfFile = fopen(argv[dyn_file_arg], "r"); if (!m_pDynConfFile) E("ERROR: Cannot open dynamic config file: %s", argv[dyn_file_arg]); else { memset(&dynamic_config, 0, sizeof(struct DynamicConfig)); } } } } void* Watchdog(void* data) { while (1) { sleep(1000); if (m_bWatchDogKicked == true) m_bWatchDogKicked = false; else E("watchdog has not been kicked. we may have a deadlock"); } return NULL; } int main(int argc, char** argv) { OMX_U8* pvirt = NULL; int result; float enc_time_sec=0.0,enc_time_usec=0.0; m_nInFd = -1; m_nOutFd = -1; m_nTimeStamp = 0; m_nFrameIn = 0; m_nFrameOut = 0; memset(&m_sMsgQ, 0, sizeof(MsgQ)); memset(&m_sProfile, 0, sizeof(m_sProfile)); parseArgs(argc, argv); D("fps=%f, bitrate=%u, width=%u, height=%u, frame bytes=%u", m_sProfile.nFramerate, m_sProfile.nBitrate, m_sProfile.nFrameWidth, m_sProfile.nFrameHeight, m_sProfile.nFrameBytes); #ifdef _MSM8974_ D("Frame stride=%u, scanlines=%u, read=%u", m_sProfile.nFramestride, m_sProfile.nFrameScanlines, m_sProfile.nFrameRead); #endif //if (m_eMode != MODE_PREVIEW && m_eMode != MODE_DISPLAY) //{ // pthread_t wd; // pthread_create(&wd, NULL, Watchdog, NULL); //} for (int x = 0; x < num_in_buffers; x++) { // mark all buffers as ready to use m_bInFrameFree[x] = OMX_TRUE; } if (m_eMode != MODE_PROFILE) { #if T_ARM m_nOutFd = open(m_sProfile.cOutFileName, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO); #else m_nOutFd = open(m_sProfile.cOutFileName,0); #endif if (m_nOutFd < 0) { E("could not open output file %s", m_sProfile.cOutFileName); CHK(1); } } pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_signal, NULL); if (m_eMode != MODE_PREVIEW) { VencTest_Initialize(); } //////////////////////////////////////// // Camera + Encode //////////////////////////////////////// if (m_eMode == MODE_LIVE_ENCODE) { CameraTest_Initialize(m_sProfile.nFramerate, m_sProfile.nFrameWidth, m_sProfile.nFrameHeight, PreviewCallback); CameraTest_Run(); } if (m_eMode == MODE_FILE_ENCODE || m_eMode == MODE_PROFILE) { int i; #if T_ARM m_nInFd = open(m_sProfile.cInFileName, O_RDONLY); #else m_nInFd = open(m_sProfile.cInFileName,1); #endif if (m_nInFd < 0) { E("could not open input file"); CHK(1); } D("going to idle state"); //SetState(OMX_StateIdle); OMX_SendCommand(m_hHandle, OMX_CommandStateSet, (OMX_U32) OMX_StateIdle, NULL); OMX_PARAM_PORTDEFINITIONTYPE portDef; portDef.nPortIndex = 0; result = OMX_GetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portDef); CHK(result); D("allocating Input buffers"); num_in_buffers = portDef.nBufferCountActual; for (i = 0; i < portDef.nBufferCountActual; i++) { OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO* pMem = new OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO; pvirt = (OMX_U8*)PmemMalloc(pMem, m_sProfile.nFrameBytes); if (pvirt == NULL) { CHK(1); } result = VencTest_RegisterYUVBuffer(&m_pInBuffers[i], (OMX_U8*) pvirt, (OMX_PTR) pMem); CHK(result); } } else if (m_eMode == MODE_LIVE_ENCODE) { D("going to idle state"); //SetState(OMX_StateIdle); OMX_SendCommand(m_hHandle, OMX_CommandStateSet, (OMX_U32) OMX_StateIdle, NULL); } int i; OMX_PARAM_PORTDEFINITIONTYPE portDef; portDef.nPortIndex = 1; result = OMX_GetParameter(m_hHandle, OMX_IndexParamPortDefinition, &portDef); CHK(result); D("allocating & calling usebuffer for Output port"); num_out_buffers = portDef.nBufferCountActual; for (i = 0; i < portDef.nBufferCountActual; i++) { void* pBuff; pBuff = malloc(portDef.nBufferSize); D("portDef.nBufferSize = %d ",portDef.nBufferSize); result = OMX_UseBuffer(m_hHandle, &m_pOutBuffers[i], (OMX_U32) PORT_INDEX_OUT, NULL, portDef.nBufferSize, (OMX_U8*) pBuff); CHK(result); } D("allocate done"); // D("Going to state " # eState"..."); while (m_eState != OMX_StateIdle) { sleep(1); } //D("Now in state " # eState); D("going to executing state"); SetState(OMX_StateExecuting); for (i = 0; i < num_out_buffers; i++) { D("filling buffer %d", i); result = OMX_FillThisBuffer(m_hHandle, m_pOutBuffers[i]); //sleep(1000); CHK(result); } if (m_eMode == MODE_FILE_ENCODE) { // encode the first frame to kick off the whole process VencTest_ReadAndEmpty(m_pInBuffers[0]); // FBTest_DisplayImage(((PmemBuffer*) m_pInBuffers[0]->pAppPrivate)->fd,0); } if (m_eMode == MODE_PROFILE) { int i; // read several frames into memory D("reading frames into memory"); for (i = 0; i < num_in_buffers; i++) { D("[%d] address 0x%x",i, m_pInBuffers[i]->pBuffer); #ifdef MAX_RES_720P read(m_nInFd, m_pInBuffers[i]->pBuffer, m_sProfile.nFrameBytes); #else // read Y first read(m_nInFd, m_pInBuffers[i]->pBuffer, m_sProfile.nFrameWidth*m_sProfile.nFrameHeight); // check alignment for offset to C OMX_U32 offset_to_c = m_sProfile.nFrameWidth * m_sProfile.nFrameHeight; const OMX_U32 C_2K = (1024*2), MASK_2K = C_2K-1, IMASK_2K = ~MASK_2K; if (offset_to_c & MASK_2K) { // offset to C is not 2k aligned, adjustment is required offset_to_c = (offset_to_c & IMASK_2K) + C_2K; } // read C read(m_nInFd, m_pInBuffers[i]->pBuffer + offset_to_c, m_sProfile.nFrameWidth*m_sProfile.nFrameHeight/2); #endif } // FBTest_Initialize(m_sProfile.nFrameWidth, m_sProfile.nFrameHeight); // loop over the mem-resident frames and encode them D("beging playing mem-resident frames..."); for (i = 0; m_nFramePlay == 0 || i < m_nFramePlay; i++) { int idx = i % num_in_buffers; if (m_bInFrameFree[idx] == OMX_FALSE) { int j; E("the expected buffer is not free, but lets find another"); idx = -1; // lets see if we can find another free buffer for (j = 0; j < num_in_buffers; j++) { if (m_bInFrameFree[j]) { idx = j; break; } } } // if we have a free buffer let's encode it if (idx >= 0) { D("encode frame %d...m_pInBuffers[idx]->pBuffer=0x%x", i,m_pInBuffers[idx]->pBuffer); m_bInFrameFree[idx] = OMX_FALSE; VencTest_EncodeFrame(m_pInBuffers[idx]->pBuffer, m_nTimeStamp); D("display frame %d...", i); // FBTest_DisplayImage(((PmemBuffer*) m_pInBuffers[idx]->pAppPrivate)->fd,0); m_nTimeStamp += 1000000 / m_sProfile.nFramerate; } else { E("wow, no buffers are free, performance " "is not so good. lets just sleep some more"); } D("sleep for %d microsec", 1000000/m_sProfile.nFramerate); sleep (1000000 / m_sProfile.nFramerate); } // FBTest_Exit(); } Msg msg; bool bQuit = false; while ((m_eMode == MODE_FILE_ENCODE || m_eMode == MODE_LIVE_ENCODE) && !bQuit) { PopMessage(&msg); switch (msg.id) { ////////////////////////////////// // FRAME IS ENCODED ////////////////////////////////// case MSG_ID_INPUT_FRAME_DONE: /*pthread_mutex_lock(&m_mutex); ++m_nFrameOut; if (m_nFrameOut == m_nFramePlay && m_nFramePlay != 0) { bQuit = true; } pthread_mutex_unlock(&m_mutex);*/ if (!bQuit && m_eMode == MODE_FILE_ENCODE) { D("pushing another frame down to encoder"); if (VencTest_ReadAndEmpty(msg.data.sBitstreamData.pBuffer)) { // we have read the last frame D("main is exiting..."); bQuit = true; } } break; case MSG_ID_OUTPUT_FRAME_DONE: D("================ writing frame %d = %d bytes to output file", m_nFrameOut+1, msg.data.sBitstreamData.pBuffer->nFilledLen); D("StopEncodeTime=%lld", GetTimeStamp()); write(m_nOutFd, msg.data.sBitstreamData.pBuffer->pBuffer, msg.data.sBitstreamData.pBuffer->nFilledLen); result = OMX_FillThisBuffer(m_hHandle, msg.data.sBitstreamData.pBuffer); if (result != OMX_ErrorNone) { CHK(result); } pthread_mutex_lock(&m_mutex); ++m_nFrameOut; if (m_nFrameOut == m_nFramePlay && m_nFramePlay != 0) { bQuit = true; } pthread_mutex_unlock(&m_mutex); break; default: E("invalid msg id %d", (int) msg.id); } // end switch (msg.id) /* // TO UNCOMMENT FOR PAUSE TESTINGS if(m_nFrameOut == 10) { E("\nGoing to Pause state\n"); SetState(OMX_StatePause); sleep(3); //REQUEST AN I FRAME AFTER PAUSE OMX_CONFIG_INTRAREFRESHVOPTYPE voprefresh; voprefresh.nPortIndex = (OMX_U32)PORT_INDEX_OUT; voprefresh.IntraRefreshVOP = OMX_TRUE; result = OMX_SetConfig(m_hHandle, OMX_IndexConfigVideoIntraVOPRefresh, &voprefresh); E("\n OMX_IndexConfigVideoIntraVOPRefresh Set Paramter port"); CHK(result); E("\nGoing to executing state\n"); SetState(OMX_StateExecuting); } */ } // end while (!bQuit) if (m_eMode == MODE_LIVE_ENCODE) { CameraTest_Exit(); close(m_nOutFd); } else if (m_eMode == MODE_FILE_ENCODE || m_eMode == MODE_PROFILE) { // deallocate pmem buffers for (int i = 0; i < num_in_buffers; i++) { PmemFree((OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO*)m_pInBuffers[i]->pAppPrivate, m_pInBuffers[i]->pBuffer, m_sProfile.nFrameBytes); delete (OMX_QCOM_PLATFORM_PRIVATE_PMEM_INFO*) m_pInBuffers[i]->pAppPrivate; } close(m_nInFd); if (m_eMode == MODE_FILE_ENCODE) { close(m_nOutFd); } if (m_pDynConfFile) { fclose(m_pDynConfFile); m_pDynConfFile = NULL; } } if (m_eMode != MODE_PREVIEW) { D("exit encoder test"); VencTest_Exit(); } pthread_mutex_destroy(&m_mutex); pthread_cond_destroy(&m_signal); /* Time Statistics Logging */ if (0 != m_sProfile.nFramerate) { enc_time_usec = m_nTimeStamp - (1000000 / m_sProfile.nFramerate); enc_time_sec =enc_time_usec/1000000; if (0 != enc_time_sec) { printf("Total Frame Rate: %f",ebd_cnt/enc_time_sec); printf("\nEncoder Bitrate :%lf Kbps",(tot_bufsize*8)/(enc_time_sec*1000)); } } else { printf("\n\n Encode Time is zero"); } printf("\nTotal Number of Frames :%d",ebd_cnt); printf("\nNumber of dropped frames during encoding:%d\n",ebd_cnt-fbd_cnt); /* End of Time Statistics Logging */ D("main has exited"); return 0; }