diff options
Diffstat (limited to 'mm-video-v4l2/vidc/venc/test/venc_test.cpp')
-rw-r--r-- | mm-video-v4l2/vidc/venc/test/venc_test.cpp | 2442 |
1 files changed, 2442 insertions, 0 deletions
diff --git a/mm-video-v4l2/vidc/venc/test/venc_test.cpp b/mm-video-v4l2/vidc/venc/test/venc_test.cpp new file mode 100644 index 00000000..7afb5bd9 --- /dev/null +++ b/mm-video-v4l2/vidc/venc/test/venc_test.cpp @@ -0,0 +1,2442 @@ +/*-------------------------------------------------------------------------- +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_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; +} |