/* * Copyright (C) 2008-2015 Allwinner Technology Co. Ltd. * Author: Ning Fang * Caoyuan Yang * * This software is confidential and proprietary and may be used * only as expressly authorized by a licensing agreement from * Softwinner Products. * * The entire notice above must be reproduced on all copies * and should not be removed. */ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ //#define LOG_TAG "venc" #include #include #include #include #include #include #include #include #include "cdc_log.h" #include "vencoder.h" #include "FrameBufferManager.h" #include "venc_device.h" #include "EncAdapter.h" #include "veAdapter.h" #include "memoryAdapter.h" #include "CdcUtil.h" #include "cdc_version.h" #include "CdcIniparserapi.h" #include "EncoderList.h" #if VENC_SUPPORT_EXT_PARAM #include #endif #define MAX_FRAME_BUFFER_NUM 32 #define AW_ENCODER_SHOW_SPEED_INFO (0) #define MAX_VENCODER_CHANNEL_NUM (16) void* OnlineThreadProcess(void* param); void* OfflineThreadProcess(void* param); extern void* EncppCreate(); extern void EncppDestroy(void* encpp); extern int EncppFunction(void* encpp, VencEncppBufferInfo* pInBuffer, VencEncppBufferInfo* pOutBuffer, VencEncppFuncParam* pEncppFunction); extern VENC_DEVICE* CreateSpecificEncoder(VENC_CODEC_TYPE format); void AddVENCPlugin(void); typedef enum VencoderCmd { VENCODER_CMD_SET_STATE_INIT = 0, VENCODER_CMD_SET_STATE_EXECUT = 1,// sync cmd VENCODER_CMD_SET_STATE_PAUSE = 2,// sync cmd VENCODER_CMD_RESET = 3,// sync cmd VENCODER_CMD_FLUSH = 4,// async cmd VENCODER_CMD_EXIT = 5,// sync cmd VENCODER_CMD_InputFrameAvailable = 6,// async cmd VENCODER_CMD_OutputStreamAvailable = 7,// async cmd }VencoderCmd; #define VENC_SEM_WAIT_REPLY_NUM (VENCODER_CMD_EXIT + 1) typedef enum VencoderState { VENCODER_STATE_IDLE = 0, VENCODER_STATE_INITED = 1, VENCODER_STATE_EXCUTING = 2, VENCODER_STATE_PAUSE = 3, }VencoderState; typedef struct ShowSpeedInfoCtx { int bEnable; int64_t nCurFrameStartTime; int64_t nCurFrameEndTime; int64_t nPeriodStartTime; int64_t nPeriodEndTime; int64_t nPeriodCostTotalTime; int64_t nPeriodFrameNum; int64_t nPeriodMaxTime; int64_t nPeriodMinTime; }ShowSpeedInfoCtx; typedef struct OverlayParam { unsigned char* dataBuf; unsigned int dataSize; VencOverlayInfoS mOverlayInfo; pthread_mutex_t mutex; unsigned int bNeedUpdateFlag; }OverlayParam; typedef struct VencContext { unsigned int mDbgVbvFullContiguousCnt; int nChannelId; OverlayParam mOverlayParam; VENC_DEVICE* pVEncDevice; void* pEncoderHandle; FrameBufferManager* pFBM; VencBaseConfig baseConfig; VencHeaderData headerData; VencInputBuffer curEncInputbuffer; VENC_CODEC_TYPE codecType; unsigned int ICVersion; int bInit; struct ScMemOpsS *memops; VeOpsS* veOpsS; void* pVeOpsSelf; ShowSpeedInfoCtx mShowSpeedInfoCtx; pthread_t processThread; VencoderState eState; CdcMessageQueue* mq; sem_t reply_sem[VENC_SEM_WAIT_REPLY_NUM]; unsigned int bNoInputFrameFlag; pthread_mutex_t mInputFrameLock; unsigned int bNoOutputStreamBufFlag; pthread_mutex_t mOutputStreamLock; VENC_RC_MODE eRcMode; unsigned int bNeedUpdateMbStatInfoFlag; unsigned int bNeedUpdateSharpParamFlag; VencCbType* pCallbacks; void* pAppData; int bEnableResetWholeVE; }VencContext; typedef enum OnlineBufNumInfo { Had_No_Online_Channel, Had_Online_Channel_One_Buf, Had_Online_Channel_Two_Buf }OnlineBufNumInfo; typedef struct OnlineVencContext { VencContext *pVencCxt[MAX_VENCODER_CHANNEL_NUM]; pthread_t onlineThread; int nValidChannelNum; unsigned int bNoInputFrameFlag; pthread_mutex_t mInputFrameLock; unsigned int bNoOutputStreamBufFlag; pthread_mutex_t mOutputStreamLock; CdcMessageQueue* mq; int nOnlineChannelIndex; OnlineBufNumInfo eOnlineBufNum; }OnlineVencContext; static OnlineVencContext *pOnlineCxt = NULL; static pthread_mutex_t OnlineMutex = PTHREAD_MUTEX_INITIALIZER; #if VENC_SUPPORT_EXT_PARAM #define VE_PARAM_DYNAMIC 0 #define VE_PARAM_STATIC 1 static int check_ve_param_file(int is_static, VencContext *pCurVencCxt, int ch_id); #endif extern struct ScMemOpsS* MemAdapterGetOpsS(); #if 0 extern VENC_DEVICE video_encoder_h264_ver1; extern VENC_DEVICE video_encoder_jpeg; extern VENC_DEVICE video_encoder_h264_ver2; extern VENC_DEVICE video_encoder_h265; extern VENC_DEVICE video_encoder_vp8; VENC_DEVICE* video_encoder_devices[] = { &video_encoder_h264_ver1, &video_encoder_jpeg, &video_encoder_h264_ver2, &video_encoder_h265, //&video_encoder_vp8, // not any product use vp8 encoder now. (bz) 0 }; #endif static int postMessgaeAndWait(VencContext* venc_ctx, int cmd, unsigned char* param1, unsigned char* param2) { CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); msg.messageId = cmd; msg.params[0] = (uintptr_t)(&venc_ctx->reply_sem[cmd]); msg.params[1] = (uintptr_t)venc_ctx; msg.params[2] = (uintptr_t)param1; msg.params[3] = (uintptr_t)param2; if(venc_ctx->baseConfig.bOnlineMode == 0) CdcMessageQueuePostMessage(venc_ctx->mq, &msg); else CdcMessageQueuePostMessage(pOnlineCxt->mq, &msg); logv("********* cmd = %d, wait reply start", cmd); CdcSemTimedWait(&venc_ctx->reply_sem[cmd], -1); logv("********* cmd = %d, wait reply finish", cmd); return 0; } static inline int64_t getCurrentTime(void) { struct timeval tv; int64_t time; gettimeofday(&tv,NULL); time = tv.tv_sec*1000000 + tv.tv_usec; return time; } static VENC_DEVICE *vencoderDeviceCreate(VENC_CODEC_TYPE type) { VENC_DEVICE *vencoder_device_handle; VENC_DEVICE *match_interface = CreateSpecificEncoder(type); logv("CreateSpecificEncoder: %p", match_interface); if(match_interface == NULL) { loge("CreateSpecificEncoder failed"); return NULL; } vencoder_device_handle = (VENC_DEVICE *)malloc(sizeof(VENC_DEVICE)); if(vencoder_device_handle == NULL) { return NULL; } memcpy(vencoder_device_handle, match_interface, sizeof(VENC_DEVICE)); return vencoder_device_handle; } static void vencoderDeviceDestroy(void *handle) { if (handle != NULL) { free(handle); } } static int updateSpeedInfo(VencContext* venc_ctx) { ShowSpeedInfoCtx* pSpeedCtx = &venc_ctx->mShowSpeedInfoCtx; pSpeedCtx->nPeriodFrameNum++; pSpeedCtx->nCurFrameEndTime = getCurrentTime(); pSpeedCtx->nPeriodEndTime = getCurrentTime(); int64_t nCurFrameCostTime = pSpeedCtx->nCurFrameEndTime - pSpeedCtx->nCurFrameStartTime; pSpeedCtx->nPeriodCostTotalTime += nCurFrameCostTime; if(pSpeedCtx->nPeriodMaxTime < nCurFrameCostTime || pSpeedCtx->nPeriodMaxTime == 0) pSpeedCtx->nPeriodMaxTime = nCurFrameCostTime; if(pSpeedCtx->nPeriodMinTime > nCurFrameCostTime || pSpeedCtx->nPeriodMinTime == 0) pSpeedCtx->nPeriodMinTime = nCurFrameCostTime; int64_t nPeriodTime = pSpeedCtx->nPeriodEndTime - pSpeedCtx->nPeriodStartTime; if(nPeriodTime > 1*1000*1000) //* 1 second { int64_t nHardwareSpeed = pSpeedCtx->nPeriodCostTotalTime/pSpeedCtx->nPeriodFrameNum; int64_t nRealSpeed = nPeriodTime/pSpeedCtx->nPeriodFrameNum; logd(" hardware_speed = %0.2f fps, real_speed = %0.2f fps, maxTime = %0.2f ms, minTime = %0.2f ms", (float)1000*1000/nHardwareSpeed, (float)1000*1000/nRealSpeed, (float)pSpeedCtx->nPeriodMaxTime/1000, (float)pSpeedCtx->nPeriodMinTime/1000); pSpeedCtx->nCurFrameStartTime = 0; pSpeedCtx->nCurFrameEndTime = 0; pSpeedCtx->nPeriodStartTime = 0; pSpeedCtx->nPeriodEndTime = 0; pSpeedCtx->nPeriodCostTotalTime = 0; pSpeedCtx->nPeriodFrameNum = 0; pSpeedCtx->nPeriodMaxTime = 0; pSpeedCtx->nPeriodMinTime = 0; } return 0; } static int encodeOneFrame(VideoEncoder* pEncoder) { int result = 0; VencContext* venc_ctx = (VencContext*)pEncoder; VencCbInputBufferDoneInfo mCbDoneInfo; memset(&mCbDoneInfo, 0 , sizeof(VencCbInputBufferDoneInfo)); VencMBModeCtrl mMbModeCtl; memset(&mMbModeCtl, 0, sizeof(VencMBModeCtrl)); int bBSBufIsFull = 0; if(!venc_ctx) { return -1; } pthread_mutex_lock(&venc_ctx->mOverlayParam.mutex); if(venc_ctx->mOverlayParam.bNeedUpdateFlag) { venc_ctx->pVEncDevice->SetParameter(venc_ctx->pEncoderHandle, VENC_IndexParamSetOverlay, (void*)&venc_ctx->mOverlayParam.mOverlayInfo); venc_ctx->mOverlayParam.bNeedUpdateFlag = 0; } pthread_mutex_unlock(&venc_ctx->mOverlayParam.mutex); struct ScMemOpsS *_memops = venc_ctx->baseConfig.memops; unsigned int phyOffset = EncAdapterGetVeAddrOffset(); if(venc_ctx->baseConfig.bOnlineChannel == 0) { if(VencFbmRequestValidBuffer(venc_ctx->pFBM, &venc_ctx->curEncInputbuffer) != 0) { return VENC_RESULT_NO_FRAME_BUFFER; } } else { memset(&venc_ctx->curEncInputbuffer, 0, sizeof(VencInputBuffer)); } VencGetParameter((VideoEncoder* )venc_ctx, VENC_IndexParamBSbufIsFull, &bBSBufIsFull); if(bBSBufIsFull == 1) { if(venc_ctx->mDbgVbvFullContiguousCnt == 0) { logw("bitstream empty buffer is full: id = %d", venc_ctx->nChannelId); } venc_ctx->mDbgVbvFullContiguousCnt++; } else if(venc_ctx->mDbgVbvFullContiguousCnt > 0) { logw("bitstream empty buffer is enough: id = %d", venc_ctx->nChannelId); venc_ctx->mDbgVbvFullContiguousCnt = 0; } if(bBSBufIsFull == 1) { if(venc_ctx->baseConfig.bOnlineChannel == 0) { VencFbmReturnValidBuffer(venc_ctx->pFBM, &venc_ctx->curEncInputbuffer); } if(venc_ctx->pCallbacks->InputBufferDone) { result = VENC_RESULT_BITSTREAM_IS_FULL; mCbDoneInfo.nResult = result; mCbDoneInfo.pInputBuffer = &venc_ctx->curEncInputbuffer; venc_ctx->pCallbacks->InputBufferDone(pEncoder, venc_ctx->pAppData, &mCbDoneInfo); } return result; } venc_ctx->curEncInputbuffer.pAddrPhyY -= phyOffset; venc_ctx->curEncInputbuffer.pAddrPhyC -= phyOffset; if(venc_ctx->mShowSpeedInfoCtx.bEnable == 1) { venc_ctx->mShowSpeedInfoCtx.nCurFrameStartTime = getCurrentTime(); if(venc_ctx->mShowSpeedInfoCtx.nPeriodStartTime == 0) venc_ctx->mShowSpeedInfoCtx.nPeriodStartTime = getCurrentTime(); } if(venc_ctx->curEncInputbuffer.bEnableCorp == 1) { if(venc_ctx->baseConfig.bOnlineChannel == 1 || venc_ctx->baseConfig.eInputFormat == VENC_PIXEL_LBC_AW) { logw("online-mode and lbc-format are not support crop function, online = %d, inputformat = %d", venc_ctx->baseConfig.bOnlineChannel, venc_ctx->baseConfig.eInputFormat); venc_ctx->curEncInputbuffer.bEnableCorp = 0; } } //* update encpp sharp param before do encode frame if(venc_ctx->pCallbacks->EventHandler) { VencIsp2VeParam mIsp2VeParam = {0}; int ret = venc_ctx->pCallbacks->EventHandler((VideoEncoder *)venc_ctx, venc_ctx->pAppData, VencEvent_UpdateIspToVeParam, 0, 0, &mIsp2VeParam); if(ret == 0) { VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamEnCameraMove, &mIsp2VeParam.mEnCameraMove); VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamEnvLv, &mIsp2VeParam.mEnvLv); VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamAeWeightLum, &mIsp2VeParam.mAeWeightLum); VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamIspAeStatus, &mIsp2VeParam.mIspAeStatus); if(venc_ctx->bNeedUpdateSharpParamFlag == 1) VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamSharpConfig, &mIsp2VeParam.mSharpParam); } if(venc_ctx->eRcMode == AW_QPMAP) { venc_ctx->pCallbacks->EventHandler((VideoEncoder *)venc_ctx, venc_ctx->pAppData, VencEvent_UpdateMbModeInfo, 0, 0, &mMbModeCtl); if(mMbModeCtl.mode_ctrl_en == 1) VencSetParameter((VideoEncoder *)venc_ctx, VENC_IndexParamMBModeCtrl, &mMbModeCtl); } venc_ctx->pCallbacks->EventHandler((VideoEncoder *)venc_ctx, venc_ctx->pAppData, VencEvent_UpdateIspMotionParam, 0, 0, NULL); } logv("pAddrPhyY = %p, pAddrPhyC = %p", venc_ctx->curEncInputbuffer.pAddrPhyY, venc_ctx->curEncInputbuffer.pAddrPhyC); CdcVeLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); result = venc_ctx->pVEncDevice->encode(venc_ctx->pEncoderHandle, &venc_ctx->curEncInputbuffer); CdcVeUnLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); if(venc_ctx->pCallbacks->EventHandler) { if(venc_ctx->bNeedUpdateMbStatInfoFlag == 1) { venc_ctx->pCallbacks->EventHandler((VideoEncoder *)venc_ctx, venc_ctx->pAppData, VencEvent_UpdateMbStatInfo, 0, 0, NULL); } if(venc_ctx->codecType == VENC_CODEC_H265 || venc_ctx->codecType == VENC_CODEC_H264) { VencVe2IspParam mVe2IspParam; if(venc_ctx->pVEncDevice->GetParameter(venc_ctx->pEncoderHandle, VENC_IndexParamVe2IspParam, &mVe2IspParam) == 0) { venc_ctx->pCallbacks->EventHandler((VideoEncoder *)venc_ctx, venc_ctx->pAppData, VencEvent_UpdateVeToIspParam, 0, 0, &mVe2IspParam); } } } if(venc_ctx->baseConfig.bOnlineChannel == 0) { VencFbmReturnValidBuffer(venc_ctx->pFBM, &venc_ctx->curEncInputbuffer); mCbDoneInfo.nResult = result; mCbDoneInfo.pInputBuffer = &venc_ctx->curEncInputbuffer; venc_ctx->pCallbacks->InputBufferDone(pEncoder, venc_ctx->pAppData, &mCbDoneInfo); } else { if(venc_ctx->pCallbacks && venc_ctx->pCallbacks->InputBufferDone) { mCbDoneInfo.nResult = result; mCbDoneInfo.pInputBuffer = &venc_ctx->curEncInputbuffer; venc_ctx->pCallbacks->InputBufferDone(pEncoder, venc_ctx->pAppData, &mCbDoneInfo); } } if(venc_ctx->mShowSpeedInfoCtx.bEnable == 1 && result == VENC_RESULT_OK) { updateSpeedInfo(venc_ctx); } return result; } static void enableCheckOnlineStatus() { int i = 0; int bHadOnlineChannel = 0; int bHadOfflineChannel = 0; int OnlineIndex = 0; for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i]) { if(pOnlineCxt->pVencCxt[i]->baseConfig.bOnlineChannel == 0) bHadOfflineChannel = 1; else if(pOnlineCxt->pVencCxt[i]->baseConfig.bOnlineChannel == 1) { bHadOnlineChannel = 1; OnlineIndex = i; } } } //* we need check online status when had onlineChannel and offlineChannel unsigned int bEnableCheckOnlineStatus = 0; if(bHadOnlineChannel == 1 && bHadOfflineChannel == 1) { logd("setup bEnableCheckOnlineStatus to 1"); bEnableCheckOnlineStatus = 1; VencSetParameter((VideoEncoder*)pOnlineCxt->pVencCxt[OnlineIndex], VENC_IndexParamEnableCheckOnlineStatus, &bEnableCheckOnlineStatus); } else if(bHadOnlineChannel == 1) { logd("setup bEnableCheckOnlineStatus to 0"); bEnableCheckOnlineStatus = 0; VencSetParameter((VideoEncoder*)pOnlineCxt->pVencCxt[OnlineIndex], VENC_IndexParamEnableCheckOnlineStatus, &bEnableCheckOnlineStatus); } } static void flushInputBuffer(VideoEncoder* pEncoder) { VencContext* venc_ctx = (VencContext*)pEncoder; VencCbInputBufferDoneInfo mCbDoneInfo; memset(&mCbDoneInfo, 0 , sizeof(VencCbInputBufferDoneInfo)); if(venc_ctx->baseConfig.bOnlineChannel == 0) { while (VencFbmGetValidBufferNum(venc_ctx->pFBM)) { if (VencFbmRequestValidBuffer(venc_ctx->pFBM, &venc_ctx->curEncInputbuffer) != 0) { logw("no inputbuffer break!"); break; } VencFbmReturnValidBuffer(venc_ctx->pFBM, &venc_ctx->curEncInputbuffer); if(venc_ctx->pCallbacks->InputBufferDone) { mCbDoneInfo.nResult = VENC_RESULT_DROP_FRAME; mCbDoneInfo.pInputBuffer = &venc_ctx->curEncInputbuffer; venc_ctx->pCallbacks->InputBufferDone(pEncoder, venc_ctx->pAppData, &mCbDoneInfo); } } } //reset input buffer VencFbmReset(venc_ctx->pFBM); } VideoEncoder* VencCreate(VENC_CODEC_TYPE eCodecType) { VencContext* venc_ctx = NULL; int i = 0; int loglevel; const char* loglevelFilePath = CdcGetConfigParamterString("cdc_log_level_file_path", NULL); loglevel = CdcGetSpecifyFilePathLogLevel(loglevelFilePath); if(loglevel == 0) { loglevel = CdcGetConfigParamterInt("cdc_log_level", 3); } if(loglevel < 2 || 6 < loglevel) { loglevel = 3; } logd("now cedarc log level:%d", loglevel); cdc_log_set_level(loglevel); LogVersionInfo(); AddVENCPlugin(); venc_ctx = (VencContext*)malloc(sizeof(VencContext)); if(!venc_ctx){ loge("malloc VencContext fail!"); return NULL; } memset(venc_ctx, 0,sizeof(VencContext)); venc_ctx->codecType = eCodecType; venc_ctx->bInit = 0; if(pthread_mutex_init(&venc_ctx->mInputFrameLock, NULL) != 0) { loge("init mutex failed"); free(venc_ctx); return NULL; } if(pthread_mutex_init(&venc_ctx->mOutputStreamLock, NULL) != 0) { loge("init mutex failed"); free(venc_ctx); return NULL; } if(pthread_mutex_init(&venc_ctx->mOverlayParam.mutex, NULL) != 0) { loge("init mutex failed"); free(venc_ctx); return NULL; } int type = VE_OPS_TYPE_NORMAL; venc_ctx->veOpsS = GetVeOpsS(type); if(venc_ctx->veOpsS == NULL) { loge("get ve ops failed , type = %d",type); free(venc_ctx); return NULL; } VeConfig mVeConfig; memset(&mVeConfig, 0, sizeof(VeConfig)); mVeConfig.nDecoderFlag = 0; mVeConfig.nEncoderFlag = 1; mVeConfig.nEnableAfbcFlag = 0; mVeConfig.nFormat = eCodecType; mVeConfig.nWidth = 0; mVeConfig.nResetVeMode = 0; venc_ctx->pVeOpsSelf = CdcVeInit(venc_ctx->veOpsS, &mVeConfig); if(venc_ctx->pVeOpsSelf == NULL) { loge("init ve ops failed"); CdcVeRelease(venc_ctx->veOpsS,venc_ctx->pVeOpsSelf); free(venc_ctx); return NULL; } char* baseAddr = CdcVeGetGroupRegAddr(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, REG_GROUP_VETOP); CdcVeLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); venc_ctx->ICVersion = EncAdapterGetICVersion(baseAddr); CdcVeUnLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); //for h264 enc use new driver from ic_1708 if(eCodecType == VENC_CODEC_H264 && venc_ctx->ICVersion >= 0x1708) eCodecType = VENC_CODEC_H264_VER2; venc_ctx->pVEncDevice = vencoderDeviceCreate(eCodecType); if(venc_ctx->pVEncDevice == NULL) { loge("VencoderDeviceCreate failed\n"); free(venc_ctx); return NULL; } venc_ctx->memops = MemAdapterGetOpsS(); if (venc_ctx->memops == NULL) { loge("MemAdapterGetOpsS failed\n"); free(venc_ctx); return NULL; } if(EncAdapterInitializeMem(venc_ctx->memops) != 0) { loge("can not set up memory runtime environment."); free(venc_ctx); return NULL; } venc_ctx->baseConfig.veOpsS = venc_ctx->veOpsS; venc_ctx->baseConfig.pVeOpsSelf = venc_ctx->pVeOpsSelf; venc_ctx->baseConfig.memops = venc_ctx->memops; venc_ctx->pEncoderHandle = venc_ctx->pVEncDevice->open(&venc_ctx->baseConfig, venc_ctx->ICVersion); if(!venc_ctx->pEncoderHandle) { logd("open VEncDevice error\n"); vencoderDeviceDestroy(venc_ctx->pVEncDevice); venc_ctx->pVEncDevice = NULL; free(venc_ctx); return NULL; } venc_ctx->mq = CdcMessageQueueCreate(16, "venc_thread"); for(i = 0; i < VENC_SEM_WAIT_REPLY_NUM; i++) { sem_init(&venc_ctx->reply_sem[i], 0, 0); } #if(AW_ENCODER_SHOW_SPEED_INFO) venc_ctx->mShowSpeedInfoCtx.bEnable = 1; #endif venc_ctx->eState = VENCODER_STATE_IDLE; return (VideoEncoder*)venc_ctx; } void VencDestroy(VideoEncoder* pEncoder) { int i = 0; int ret = 0; int nRealValidChannelNum = 0; VencContext* venc_ctx = (VencContext*)pEncoder; if (pEncoder == NULL) { loge("pEncoder is NULL."); return ; } if(venc_ctx->eState != VENCODER_STATE_IDLE) { if(venc_ctx->baseConfig.bOnlineMode == 0) { postMessgaeAndWait(venc_ctx, VENCODER_CMD_EXIT, NULL, NULL); pthread_join(venc_ctx->processThread, (void**)&ret); } else { pthread_mutex_lock(&OnlineMutex); if(pOnlineCxt) { postMessgaeAndWait(venc_ctx, VENCODER_CMD_EXIT, NULL, NULL); //* need re-enable checkOnlineStatus when had channel destroy enableCheckOnlineStatus(); PRINTF_CODE_POS for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i]) nRealValidChannelNum++; } PRINTF_CODE_POS logd("nRealValidChannelNum = %d", nRealValidChannelNum); if(nRealValidChannelNum == 0) { pthread_join(pOnlineCxt->onlineThread, (void**)&ret); if(pOnlineCxt->mq) CdcMessageQueueDestroy(pOnlineCxt->mq); pthread_mutex_destroy(&pOnlineCxt->mInputFrameLock); pthread_mutex_destroy(&pOnlineCxt->mOutputStreamLock); free(pOnlineCxt); pOnlineCxt = NULL; } } pthread_mutex_unlock(&OnlineMutex); } venc_ctx->pVEncDevice->uninit(venc_ctx->pEncoderHandle); if(venc_ctx->ICVersion == 0x1639) { if(venc_ctx->baseConfig.nDstWidth >= 3840 || venc_ctx->baseConfig.nDstHeight >= 2160) { CdcVeUnInitEncoderPerformance(venc_ctx->baseConfig.veOpsS, venc_ctx->baseConfig.pVeOpsSelf, 1); } else { CdcVeUnInitEncoderPerformance(venc_ctx->baseConfig.veOpsS, venc_ctx->baseConfig.pVeOpsSelf, 0); logd("VeUninitEncoderPerformance"); } } flushInputBuffer(pEncoder); if(venc_ctx->pFBM) { VencFbmDestroy(venc_ctx->pFBM); venc_ctx->pFBM = NULL; } venc_ctx->eState = VENCODER_STATE_IDLE; } if(venc_ctx->mq) { CdcMessageQueueDestroy(venc_ctx->mq); } for(i = 0; i < VENC_SEM_WAIT_REPLY_NUM; i++) { sem_destroy(&venc_ctx->reply_sem[i]); } pthread_mutex_destroy(&venc_ctx->mInputFrameLock); pthread_mutex_destroy(&venc_ctx->mOutputStreamLock); pthread_mutex_destroy(&venc_ctx->mOverlayParam.mutex); if(venc_ctx->mOverlayParam.dataBuf) free(venc_ctx->mOverlayParam.dataBuf); if(venc_ctx->pVEncDevice) { venc_ctx->pVEncDevice->close(venc_ctx->pEncoderHandle); vencoderDeviceDestroy(venc_ctx->pVEncDevice); venc_ctx->pVEncDevice = NULL; venc_ctx->pEncoderHandle = NULL; } EncAdpaterRelease(venc_ctx->memops); if(venc_ctx->veOpsS) { if(venc_ctx->baseConfig.bOnlineChannel) CdcVeSetOnlineChannel(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, 0); CdcVeRelease(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); } free(venc_ctx); } int VencInit(VideoEncoder* pEncoder, VencBaseConfig* pConfig) { int i = 0; int result = 0; VencContext* venc_ctx = (VencContext*)pEncoder; PRINTF_CODE_POS if(pEncoder == NULL || pConfig == NULL || venc_ctx->bInit) { loge("InitVideoEncoder, param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->eState != VENCODER_STATE_IDLE) { logw("the state[%d] is not idle when call init", venc_ctx->eState); return VENC_RESULT_ERROR; } logd("bOnlineMode = %d, bOnlineChannel = %d", pConfig->bOnlineMode, pConfig->bOnlineChannel); logd("lbc2.5 = %d, 2.0 = %d, 1.5 = %d, format = %d", pConfig->bLbcLossyComEnFlag2_5x, pConfig->bLbcLossyComEnFlag2x, pConfig->bLbcLossyComEnFlag1_5x, pConfig->eInputFormat); pConfig->memops = venc_ctx->memops; pConfig->veOpsS = venc_ctx->veOpsS; pConfig->pVeOpsSelf = venc_ctx->pVeOpsSelf; venc_ctx->pFBM = VencFbmCreate(MAX_FRAME_BUFFER_NUM, pConfig->memops, (void *)venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); if(venc_ctx->pFBM == NULL) { loge("venc_ctx->pFBM == NULL"); return VENC_RESULT_NO_MEMORY; } //logd("(f:%s, l:%d)", __FUNCTION__, __LINE__); if(venc_ctx->ICVersion == 0x1639) { if(pConfig->nDstWidth >= 3840 || pConfig->nDstHeight>= 2160) { CdcVeInitEncoderPerformance(pConfig->veOpsS, pConfig->pVeOpsSelf, 1); } else { CdcVeInitEncoderPerformance(pConfig->veOpsS, pConfig->pVeOpsSelf, 0); logd("VeInitEncoderPerformance"); } } //logd("(f:%s, l:%d)", __FUNCTION__, __LINE__); memcpy(&venc_ctx->baseConfig, pConfig, sizeof(VencBaseConfig)); venc_ctx->baseConfig.veOpsS = venc_ctx->veOpsS; venc_ctx->baseConfig.pVeOpsSelf = venc_ctx->pVeOpsSelf; #if VENC_SUPPORT_EXT_PARAM check_ve_param_file(VE_PARAM_STATIC, venc_ctx, venc_ctx->nChannelId); #endif result = venc_ctx->pVEncDevice->init(venc_ctx->pEncoderHandle, &venc_ctx->baseConfig); if(VENC_RESULT_OK == result) { venc_ctx->bInit = 1; } else { loge("venc_init_fail"); } if(pConfig->bOnlineMode == 1) { int bNeedCreateThreadFlag = 0; pthread_mutex_lock(&OnlineMutex); if(pOnlineCxt == NULL) { pOnlineCxt = calloc(1, sizeof(OnlineVencContext)); if(pOnlineCxt == NULL) { loge("calloc failed, size = %d", sizeof(OnlineVencContext)); } pOnlineCxt->nOnlineChannelIndex = -1; pOnlineCxt->eOnlineBufNum = Had_No_Online_Channel; pOnlineCxt->mq = CdcMessageQueueCreate(32, "vencOn_thread"); if(pthread_mutex_init(&pOnlineCxt->mInputFrameLock, NULL) != 0) { loge("init mutex failed"); free(pOnlineCxt); pthread_mutex_unlock(&OnlineMutex); return VENC_RESULT_ERROR; } if(pthread_mutex_init(&pOnlineCxt->mOutputStreamLock, NULL) != 0) { loge("init mutex failed"); free(pOnlineCxt); pthread_mutex_unlock(&OnlineMutex); return VENC_RESULT_ERROR; } bNeedCreateThreadFlag = 1; } if(pOnlineCxt) { for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i] == NULL) { venc_ctx->nChannelId = i; pOnlineCxt->pVencCxt[i] = venc_ctx; pOnlineCxt->nValidChannelNum++; if(venc_ctx->baseConfig.bOnlineChannel == 1) pOnlineCxt->nOnlineChannelIndex = i; break; } } if(i >= MAX_VENCODER_CHANNEL_NUM) { loge("cannot find empty pVencCxt: %d", i); return -1; } } if(pConfig->bOnlineChannel) { if(pConfig->nOnlineShareBufNum == 1) pOnlineCxt->eOnlineBufNum = Had_Online_Channel_One_Buf; if(pConfig->nOnlineShareBufNum == 2) pOnlineCxt->eOnlineBufNum = Had_Online_Channel_Two_Buf; } logd("pOnlineCxt->eOnlineBufNum = %d", pOnlineCxt->eOnlineBufNum); enableCheckOnlineStatus(); if(bNeedCreateThreadFlag == 1) pthread_create(&pOnlineCxt->onlineThread, NULL, OnlineThreadProcess, NULL); pthread_mutex_unlock(&OnlineMutex); } else { pthread_create(&venc_ctx->processThread, NULL, OfflineThreadProcess, (void*)venc_ctx); } PRINTF_CODE_POS postMessgaeAndWait(venc_ctx, VENCODER_CMD_SET_STATE_INIT, NULL, NULL); return result; } int VencStart(VideoEncoder* pEncoder) { VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("VencoderStart, param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->eState != VENCODER_STATE_INITED && venc_ctx->eState != VENCODER_STATE_PAUSE) { logw("the state[%d] is not inited or pause when call start", venc_ctx->eState); return VENC_RESULT_ERROR; } PRINTF_CODE_POS postMessgaeAndWait(venc_ctx, VENCODER_CMD_SET_STATE_EXECUT, NULL, NULL); return VENC_RESULT_OK; } int VencPause(VideoEncoder* pEncoder) { VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("VencoderPause, param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->eState != VENCODER_STATE_EXCUTING) { logw("the state[%d] is not excuting when call pause", venc_ctx->eState); return VENC_RESULT_ERROR; } postMessgaeAndWait(venc_ctx, VENCODER_CMD_SET_STATE_PAUSE, NULL, NULL); return VENC_RESULT_OK; } int VencReset(VideoEncoder* pEncoder) { int result = 0; VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("VencReset, param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->eState != VENCODER_STATE_EXCUTING && venc_ctx->eState != VENCODER_STATE_PAUSE) { logw("the state[%d] is not excuting or pause when call reset", venc_ctx->eState); return VENC_RESULT_ERROR; } postMessgaeAndWait(venc_ctx, VENCODER_CMD_RESET, NULL, NULL); return result; } int VencFlush(VideoEncoder* pEncoder, VencFlushType eFlushType) { int result = 0; VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("VencReset, param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->eState == VENCODER_STATE_IDLE) { logw("flush invalid when state is idle"); return VENC_RESULT_ERROR; } postMessgaeAndWait(venc_ctx, VENCODER_CMD_FLUSH, (unsigned char*)eFlushType, NULL); return result; } static int updateOverlayParam(VencContext* venc_ctx, VencOverlayInfoS *pSrcOverlayInfo) { int i = 0; int totalOverlayDataLen = 0; OverlayParam* pDstOverlay = &venc_ctx->mOverlayParam; unsigned char* pCurBuf = NULL; pthread_mutex_lock(&pDstOverlay->mutex); for(i = 0; i < pSrcOverlayInfo->blk_num; i++) totalOverlayDataLen += pSrcOverlayInfo->overlayHeaderList[i].bitmap_size; if(totalOverlayDataLen > pDstOverlay->dataSize) { if(pDstOverlay->dataBuf) free(pDstOverlay->dataBuf); pDstOverlay->dataBuf = malloc(totalOverlayDataLen); if(pDstOverlay->dataBuf == NULL) { loge("malloc failed, size = %d", totalOverlayDataLen); pthread_mutex_unlock(&pDstOverlay->mutex); return -1; } memset(pDstOverlay->dataBuf, 0, totalOverlayDataLen); pDstOverlay->dataSize = totalOverlayDataLen; } memcpy(&pDstOverlay->mOverlayInfo, pSrcOverlayInfo, sizeof(VencOverlayInfoS)); pCurBuf = pDstOverlay->dataBuf; for(i = 0; i < pSrcOverlayInfo->blk_num; i++) { memcpy(pCurBuf, pSrcOverlayInfo->overlayHeaderList[i].overlay_blk_addr, pSrcOverlayInfo->overlayHeaderList[i].bitmap_size); pDstOverlay->mOverlayInfo.overlayHeaderList[i].overlay_blk_addr = pCurBuf; pDstOverlay->mOverlayInfo.overlayHeaderList[i].bitmap_size = pSrcOverlayInfo->overlayHeaderList[i].bitmap_size; pCurBuf += pSrcOverlayInfo->overlayHeaderList[i].bitmap_size; } pDstOverlay->bNeedUpdateFlag = 1; pthread_mutex_unlock(&pDstOverlay->mutex); return 0; } int VencGetParameter(VideoEncoder* pEncoder, VENC_INDEXTYPE indexType, void* paramData) { CEDARC_UNUSE(VencGetParameter); VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("Type(%d) pEncoder is NULL!", indexType); return -1; } return venc_ctx->pVEncDevice->GetParameter(venc_ctx->pEncoderHandle, indexType, paramData); } int VencSetParameter(VideoEncoder* pEncoder, VENC_INDEXTYPE indexType, void* paramData) { int ret = 0; VencContext* venc_ctx = (VencContext*)pEncoder; int setParamInThread = 0; if(venc_ctx == NULL) { loge("Type(%d) pEncoder is NULL!", indexType); return -1; } if(indexType == VENC_IndexParamH264Param) { VencH264Param *pH264Param = (VencH264Param *)paramData; venc_ctx->eRcMode = pH264Param->sRcParam.eRcMode; } else if(indexType == VENC_IndexParamH265Param) { VencH265Param *pH265Param = (VencH265Param *)paramData; venc_ctx->eRcMode = pH265Param->sRcParam.eRcMode; } else if(indexType == VENC_IndexParamMBInfoOutput) { VencMBInfo *pMBInfo = (VencMBInfo *)paramData; if(pMBInfo->num_mb > 0 && pMBInfo->p_para) venc_ctx->bNeedUpdateMbStatInfoFlag = 1; } else if(indexType == VENC_IndexParamEnableEncppSharp) { venc_ctx->bNeedUpdateSharpParamFlag = *((unsigned int*)paramData); } else if(indexType == VENC_IndexParamEncAndDecCase) { //* enable "reset the whole ve when call resetVe()" int ve_is_decoding = *((int *)paramData); venc_ctx->bEnableResetWholeVE = ve_is_decoding ? 1 : 0; } if(indexType == VENC_IndexParamSetOverlay) { return updateOverlayParam(venc_ctx, (VencOverlayInfoS *)paramData); } if(indexType == VENC_IndexParamEnableRecRefBufReduceFunc) { if(venc_ctx->bInit == 1) { logw("The encoder has been initialized, Please use this interface before initialization."); return 0; } } logv("indexType = %d, gdcIndex = %d", indexType, VENC_IndexParamGdcConfig); //* sync mutex in sub-encoder when gdc and sharp config, as it will call every frame //* and if sync by CdcVeLock, it cost too much time if(indexType == VENC_IndexParamGdcConfig || indexType == VENC_IndexParamSharpConfig) { ret = venc_ctx->pVEncDevice->SetParameter(venc_ctx->pEncoderHandle, indexType, paramData); } else { CdcVeLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); ret = venc_ctx->pVEncDevice->SetParameter(venc_ctx->pEncoderHandle, indexType, paramData); CdcVeUnLock(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf); } return ret; } int VencGetValidOutputBufNum(VideoEncoder* pEncoder) { CEDARC_UNUSE(VencGetValidOutputBufNum); VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } return venc_ctx->pVEncDevice->ValidBitStreamFrameNum(venc_ctx->pEncoderHandle); } int VencDequeueOutputBuf(VideoEncoder* pEncoder, VencOutputBuffer* pBuffer) { VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL || pBuffer == NULL) { loge("param is NULL venc_ctx %p pBuffer %p", venc_ctx, pBuffer); return VENC_RESULT_NULL_PTR; } if(venc_ctx->pVEncDevice->GetOneBitStreamFrame(venc_ctx->pEncoderHandle, pBuffer)!=0) { return VENC_RESULT_BITSTREAM_IS_EMPTY; } return 0; } int VencQueueOutputBuf(VideoEncoder* pEncoder, VencOutputBuffer* pBuffer) { VencContext* venc_ctx = (VencContext*)pEncoder; if(!venc_ctx || (venc_ctx->baseConfig.bOnlineMode && !pOnlineCxt) || !pBuffer) { loge("param is NULL venc_ctx %p pBuffer %p", venc_ctx, pBuffer); return VENC_RESULT_NULL_PTR; } if(venc_ctx->pVEncDevice->FreeOneBitStreamFrame(venc_ctx->pEncoderHandle, pBuffer)!=0) { return -1; } if(venc_ctx->baseConfig.bOnlineMode == 0) { pthread_mutex_lock(&venc_ctx->mOutputStreamLock); if(venc_ctx->bNoOutputStreamBufFlag == 1) { CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); msg.messageId = VENCODER_CMD_OutputStreamAvailable; CdcMessageQueuePostMessage(venc_ctx->mq, &msg); venc_ctx->bNoOutputStreamBufFlag = 0; } pthread_mutex_unlock(&venc_ctx->mOutputStreamLock); } else { //* just send msg for online channel; not for offline channel. //* if you do not understand, please look func of checkIsReady_online1Buf() pthread_mutex_lock(&pOnlineCxt->mOutputStreamLock); if(venc_ctx->baseConfig.bOnlineChannel == 1 && pOnlineCxt->bNoOutputStreamBufFlag == 1) { CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); msg.messageId = VENCODER_CMD_OutputStreamAvailable; CdcMessageQueuePostMessage(pOnlineCxt->mq, &msg); pOnlineCxt->bNoOutputStreamBufFlag = 0; } pthread_mutex_unlock(&pOnlineCxt->mOutputStreamLock); } return 0; } int VencAllocateInputBuf(VideoEncoder* pEncoder, VencAllocateBufferParam *pBufferParam, VencInputBuffer* dst_inputBuf) { VencContext* venc_ctx = (VencContext*)pEncoder; if(pEncoder == NULL || pBufferParam == NULL || dst_inputBuf == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } if(venc_ctx->pFBM == NULL) { loge("venc_ctx->pFBM == NULL, must call InitVideoEncoder firstly"); return VENC_RESULT_NO_RESOURCE; } PRINTF_CODE_POS if(VencFbmAllocateBuffer(venc_ctx->pFBM, pBufferParam, dst_inputBuf)!=0) { loge("allocat inputbuffer failed"); return VENC_RESULT_NO_MEMORY; } return 0; } int VencQueueInputBuf(VideoEncoder* pEncoder, VENC_IN VencInputBuffer *inputbuffer) { VencContext* venc_ctx = (VencContext*)pEncoder; int nSemCnt = 0; if(pEncoder == NULL || inputbuffer == NULL || (venc_ctx->baseConfig.bOnlineMode && !pOnlineCxt)) { loge("param is NULL: pEncoder = %p, inputbuffer = %p", pEncoder, inputbuffer); return VENC_RESULT_NULL_PTR; } if(venc_ctx->pFBM == NULL) { loge("venc_ctx->pFBM == NULL, must call InitVideoEncoder firstly"); return VENC_RESULT_NO_RESOURCE; } if(VencFbmAddValidBuffer(venc_ctx->pFBM, inputbuffer) != 0) { logv("AddValidBuffer failed"); return -1; } if(venc_ctx->baseConfig.bOnlineMode == 0) { pthread_mutex_lock(&venc_ctx->mInputFrameLock); if(venc_ctx->bNoInputFrameFlag == 1) { venc_ctx->bNoInputFrameFlag = 0; CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); msg.messageId = VENCODER_CMD_InputFrameAvailable; CdcMessageQueuePostMessage(venc_ctx->mq, &msg); } pthread_mutex_unlock(&venc_ctx->mInputFrameLock); } else { pthread_mutex_lock(&pOnlineCxt->mInputFrameLock); if(pOnlineCxt->bNoInputFrameFlag == 1) { pOnlineCxt->bNoInputFrameFlag = 0; CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); msg.messageId = VENCODER_CMD_InputFrameAvailable; CdcMessageQueuePostMessage(pOnlineCxt->mq, &msg); } pthread_mutex_unlock(&pOnlineCxt->mInputFrameLock); } return 0; } int VencGetValidInputBufNum(VideoEncoder* pEncoder) { CEDARC_UNUSE(VencGetValidInputBufNum); VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } return VencFbmGetValidBufferNum(venc_ctx->pFBM); } int VencGetVeIommuAddr(VideoEncoder* pEncoder, struct user_iommu_param *pIommuBuf) { VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL || pIommuBuf == NULL) { loge("param is NULL, venc_ctx %p pIommuBuf %p", venc_ctx, pIommuBuf); return VENC_RESULT_NULL_PTR; } CdcVeGetIommuAddr(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, pIommuBuf); return VENC_RESULT_OK; } int VencFreeVeIommuAddr(VideoEncoder* pEncoder, struct user_iommu_param *pIommuBuf) { VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL || pIommuBuf == NULL) { loge("param is NULL, venc_ctx %p pIommuBuf %p", venc_ctx, pIommuBuf); return VENC_RESULT_NULL_PTR; } CdcVeFreeIommuAddr(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, pIommuBuf); return VENC_RESULT_OK; } int VencSetFreq(VideoEncoder* pEncoder, int nVeFreq) { CEDARC_UNUSE(VencSetFreq); VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } int ret; ret = CdcVeSetSpeed(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, nVeFreq); if(ret < 0) loge("VideoEncoderSetFreq %d error, ret is %d\n", nVeFreq, ret); return ret; } int VencSetDdrMode(VideoEncoder* pEncoder, int nDdrType) { CEDARC_UNUSE(VencSetDdrMode); VencContext* venc_ctx = (VencContext*)pEncoder; if(venc_ctx == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } CdcVeSetDdrMode(venc_ctx->veOpsS, venc_ctx->pVeOpsSelf, nDdrType); return VENC_RESULT_OK; } int VencSetCallbacks(VideoEncoder* pEncoder, VencCbType* pCallbacks, void* pAppData) { VencContext* venc_ctx = (VencContext*)pEncoder; if(pEncoder == NULL || pCallbacks == NULL) { loge("VencSetCallbacks, param is NULL: %p, %p", pEncoder, pCallbacks); return VENC_RESULT_NULL_PTR; } venc_ctx->pCallbacks = pCallbacks; venc_ctx->pAppData = pAppData; return 0; } int VencJpegEnc(JpegEncInfo* pJpegInfo, EXIFInfo* pExifInfo, void* pOutBuffer, int* pOutBufferSize) { CEDARC_UNUSE(VencJpegEnc); VencAllocateBufferParam bufferParam; VideoEncoder* pVideoEnc = NULL; VencInputBuffer inputBuffer; VencOutputBuffer outputBuffer; int result = 0; struct user_iommu_param iommu_buffer; int ion_fd = -1; aw_ion_user_handle_t handle_ion = ION_USER_HANDLE_INIT_VALUE; int nBufFd = -1; unsigned char memory_type; if (!pJpegInfo || !pExifInfo || !pOutBuffer || !pOutBufferSize) { loge("param is null, pJpegInfo %p pExifInfo %p pOutBuffer %p pOutBufferSize %p", pJpegInfo, pExifInfo, pOutBuffer, pOutBufferSize); return VENC_RESULT_NULL_PTR; } memory_type = CdcIonGetMemType(); memset(&inputBuffer, 0, sizeof(VencInputBuffer)); logd("memory_type[%d](0:normal, 1:iommu), pAddrPhyY[%p], pAddrPhyC[%p],\ quality[%d], nShareBufFd[%d], cropFlag[%d]\n", memory_type, pJpegInfo->pAddrPhyY, pJpegInfo->pAddrPhyC, pJpegInfo->quality, pJpegInfo->nShareBufFd, pJpegInfo->bEnableCorp); logd("input_size[%dx%d], output_size[%dx%d], stride[%d], color_format[%d]\n", pJpegInfo->sBaseInfo.nInputWidth, pJpegInfo->sBaseInfo.nInputHeight, pJpegInfo->sBaseInfo.nDstWidth, pJpegInfo->sBaseInfo.nDstHeight, pJpegInfo->sBaseInfo.nStride, pJpegInfo->sBaseInfo.eInputFormat); logd("thumb_size[%dx%d]\n", pExifInfo->ThumbWidth, pExifInfo->ThumbHeight); pVideoEnc = VencCreate(VENC_CODEC_JPEG); VencSetParameter(pVideoEnc, VENC_IndexParamJpegExifInfo, pExifInfo); VencSetParameter(pVideoEnc, VENC_IndexParamJpegQuality, &pJpegInfo->quality); if(VencInit(pVideoEnc, &pJpegInfo->sBaseInfo) != 0) { result = -1; goto ERROR; } if(pJpegInfo->bNoUseAddrPhy) { bufferParam.nSizeY = pJpegInfo->sBaseInfo.nStride*pJpegInfo->sBaseInfo.nInputHeight; bufferParam.nSizeC = bufferParam.nSizeY>>1; if(VencAllocateInputBuf(pVideoEnc, &bufferParam, &inputBuffer)<0) { result = -1; goto ERROR; } } else { //get ion fd ion_fd = CdcIonOpen(); if (ion_fd < 0) { loge("open ion fd failed \n"); result = -1; goto ERROR; } //import ion buffer handle result = CdcIonImport(ion_fd, pJpegInfo->nShareBufFd, &handle_ion); if (result < 0) { loge("CdcIonImport get handle failed\n"); result = -1; goto ERROR; } //get ion buffer fd nBufFd = CdcIonGetFd(ion_fd, (uintptr_t)handle_ion); if (nBufFd < 0) { loge("CdcIonGetFd get fd failed\n"); result = -1; goto ERROR; } //get iommu addr if(memory_type == MEMORY_IOMMU) { iommu_buffer.fd = nBufFd; VencGetVeIommuAddr(pVideoEnc, &iommu_buffer); inputBuffer.pAddrPhyY = (unsigned char*)(uintptr_t)iommu_buffer.iommu_addr; inputBuffer.pAddrPhyC = inputBuffer.pAddrPhyY + pJpegInfo->sBaseInfo.nStride * ((pJpegInfo->sBaseInfo.nInputHeight + 15) & (~15)); } else { inputBuffer.pAddrPhyY = (unsigned char *) CdcIonGetPhyAdr(ion_fd, (uintptr_t)handle_ion); inputBuffer.pAddrPhyC = inputBuffer.pAddrPhyY + pJpegInfo->sBaseInfo.nStride * pJpegInfo->sBaseInfo.nInputHeight; } } VencStart(pVideoEnc); inputBuffer.bEnableCorp = pJpegInfo->bEnableCorp; inputBuffer.sCropInfo.nLeft = pJpegInfo->sCropInfo.nLeft; inputBuffer.sCropInfo.nTop = pJpegInfo->sCropInfo.nTop; inputBuffer.sCropInfo.nWidth = pJpegInfo->sCropInfo.nWidth; inputBuffer.sCropInfo.nHeight = pJpegInfo->sCropInfo.nHeight; if(pJpegInfo->bNoUseAddrPhy) { memcpy(inputBuffer.pAddrVirY, pJpegInfo->pAddrPhyY, bufferParam.nSizeY); memcpy(inputBuffer.pAddrVirC, pJpegInfo->pAddrPhyC, bufferParam.nSizeC); inputBuffer.bNeedFlushCache = 1; } VencQueueInputBuf(pVideoEnc, &inputBuffer); result = -1; int timeoutNum = 400; while(result != 0) { result = VencDequeueOutputBuf(pVideoEnc, &outputBuffer); usleep(5*1000); timeoutNum--; if(timeoutNum <= 0) { loge("dequeue out buffer timeout"); break; } } if(result == 0) { memcpy(pOutBuffer, outputBuffer.pData0, outputBuffer.nSize0); if(outputBuffer.nSize1) { memcpy(((unsigned char*)pOutBuffer + outputBuffer.nSize0), \ outputBuffer.pData1, outputBuffer.nSize1); *pOutBufferSize = outputBuffer.nSize0 + outputBuffer.nSize1; } else { *pOutBufferSize = outputBuffer.nSize0; } VencQueueOutputBuf(pVideoEnc, &outputBuffer); } //deattach buf fd from ve if(memory_type == MEMORY_IOMMU) VencFreeVeIommuAddr(pVideoEnc, &iommu_buffer); //close buf fd if(nBufFd != -1) { result = CdcIonClose(nBufFd); if(result < 0) { loge("CdcIonClose close buf fd error\n"); result = -1; goto ERROR; } } //free ion handle if(handle_ion) { result = CdcIonFree(ion_fd, handle_ion); if(result < 0) { loge("CdcIonFree free ion_handle error\n"); goto ERROR; } } if (ion_fd != -1) { result = CdcIonClose(ion_fd); if(result < 0) { loge("CdcIonClose ion fd error\n"); goto ERROR; } ion_fd = -1; } ERROR: if(pVideoEnc) { VencPause(pVideoEnc); VencDestroy(pVideoEnc); } return result; } VideoEncoderEncpp* VencEncppCreate() { int loglevel; const char* loglevelFilePath = CdcGetConfigParamterString("cdc_log_level_file_path", NULL); loglevel = CdcGetSpecifyFilePathLogLevel(loglevelFilePath); if(loglevel == 0) { loglevel = CdcGetConfigParamterInt("cdc_log_level", 3); } if(loglevel < 2 || 6 < loglevel) { loglevel = 3; } logd("now cedarc log level:%d", loglevel); cdc_log_set_level(loglevel); LogVersionInfo(); return (VideoEncoderEncpp*)EncppCreate(); } int VencEncppDestroy(VideoEncoderEncpp* pEncpp) { if(pEncpp == NULL) { loge("param is NULL"); return VENC_RESULT_NULL_PTR; } EncppDestroy((void*)pEncpp); return VENC_RESULT_OK; } int VencEncppFunction(VideoEncoderEncpp* pEncpp, VencEncppBufferInfo* pInBuffer, VencEncppBufferInfo* pOutBuffer, VencEncppFuncParam* pEncppFunction) { if (!pEncpp || !pInBuffer || !pOutBuffer || !pEncppFunction) { loge("param is null, pEncpp %p pInBuffer %p pOutBuffer %p pEncppFunction %p", pEncpp, pInBuffer, pOutBuffer, pEncppFunction); return VENC_RESULT_NULL_PTR; } int ret = EncppFunction((void*)pEncpp, pInBuffer, pOutBuffer, pEncppFunction); return ret; } /* /proc/[pid]/maps */ static int GetLocalPathFromProcessMapsVenc(char *localPath, int len) { #define LOCAL_LIB "libvencoder.so" char path[512] = {0}; char line[1024] = {0}; FILE *file = NULL; char *strLibPos = NULL; int ret = -1; memset(localPath, 0x00, len); sprintf(path, "/proc/%d/maps", getpid()); file = fopen(path, "r"); if (file == NULL) { loge("fopen failure, errno(%d)", errno); ret = -1; goto out; } while (fgets(line, 1023, file) != NULL) { if ((strLibPos = strstr(line, LOCAL_LIB)) != NULL) { char *rootPathPos = NULL; int localPathLen = 0; rootPathPos = strchr(line, '/'); if (rootPathPos == NULL) { loge("some thing error, cur line '%s'", line); ret = -1; goto out; } localPathLen = strLibPos - rootPathPos - 1; if (localPathLen > len -1) { loge("localPath too long :%s ", localPath); ret = -1; goto out; } memcpy(localPath, rootPathPos, localPathLen); ret = 0; goto out; } } loge("Are you kidding? not found?"); out: if (file) { fclose(file); } return ret; } typedef void VENCPluginEntry(void); void AddVENCPluginSingle(char *lib) { void *libFd = NULL; if(lib == NULL) { loge(" open lib == NULL "); return; } libFd = dlopen(lib, RTLD_NOW); VENCPluginEntry *PluginInit = NULL; if (libFd == NULL) { loge("dlopen '%s' fail: %s", lib, dlerror()); return ; } PluginInit = dlsym(libFd, "CedarPluginVENCInit"); if (PluginInit == NULL) { logw("Invalid plugin, CedarPluginVDInit not found."); return; } logv("vencoder open lib: %s", lib); PluginInit(); /* init plugin */ return ; } #ifdef CONFIG_COMPILE_STATIC_LIB extern void CedarPluginVENCInit_h264(); extern void CedarPluginVENCInit_h265(); extern void CedarPluginVENCInit_jpeg(); void AddVENCPlugin(void) { #ifdef CONF_ENABLE_VENC_H264 CedarPluginVENCInit_h264(); #endif #ifdef CONF_ENABLE_VENC_H265 CedarPluginVENCInit_h265(); #endif #ifdef CONF_ENABLE_VENC_JPEG CedarPluginVENCInit_jpeg(); #endif } #else /* executive when load */ //static void AddVDPlugin(void) __attribute__((constructor)); void AddVENCPlugin(void) { CEDARC_UNUSE(AddVENCPlugin); char localPath[512]; char slash[4] = "/"; char loadLib[512]; struct dirent **namelist = NULL; int num = 0, index = 0; int pathLen = 0; int ret; logd("add vencoder plugin from so"); memset(localPath, 0, 512); memset(loadLib, 0, 512); //scan_local_path: ret = GetLocalPathFromProcessMapsVenc(localPath, 512); if (ret != 0) { logw("get local path failure, scan /system/lib "); goto scan_system_lib; } num = scandir(localPath, &namelist, NULL, NULL); if (num <= 0) { logw("scandir failure, errno(%d), scan /system/lib ", errno); goto scan_system_lib; } strcat(localPath, slash); pathLen = strlen(localPath); strcpy(loadLib, localPath); logw("get local path: %s", localPath); for(index = 0; index < num; index++) { if((strstr((namelist[index])->d_name, "libvenc_h264.so") != NULL) || (strstr((namelist[index])->d_name, "libvenc_h265.so") != NULL) || (strstr((namelist[index])->d_name, "libvenc_jpeg.so") != NULL)) { loadLib[pathLen] = '\0'; strcat(loadLib, (namelist[index])->d_name); logw("load so: %s ", loadLib); AddVENCPluginSingle(loadLib); } free(namelist[index]); namelist[index] = NULL; } scan_system_lib: // TODO: scan /system/lib return; } #endif static int doReset(VencContext *pVencCxt) { int ret = 0; //reset input buffer ret = VencFbmReset(pVencCxt->pFBM); if(ret) return -1; //reset output buffer ret = pVencCxt->pVEncDevice->ResetBitStreamFrame(pVencCxt->pEncoderHandle); if(ret) return -1; return ret; } static int doFlush(VencContext *pVencCxt, VencFlushType eFlushType) { int ret = 0; int nOutputUnReturnNum = 0; if(eFlushType == VENC_FLUSH_INPUT_BUFFER) { flushInputBuffer((VideoEncoder *) pVencCxt); } else if(eFlushType == VENC_FLUSH_OUTPUT_BUFFER) { nOutputUnReturnNum = pVencCxt->pVEncDevice->GetBitStreamUnReturnNum(pVencCxt->pEncoderHandle); if(nOutputUnReturnNum == 0) { ret = pVencCxt->pVEncDevice->ResetBitStreamFrame(pVencCxt->pEncoderHandle); if(ret) return -1; } else { loge("flush output buffer failed as caller not return all output buffer to vencoder, nOutputUnReturnNum = %d", nOutputUnReturnNum); } } else if(eFlushType == VENC_FLUSH_IN_AND_OUT_BUFFER) { flushInputBuffer((VideoEncoder *) pVencCxt); nOutputUnReturnNum = pVencCxt->pVEncDevice->GetBitStreamUnReturnNum(pVencCxt->pEncoderHandle); if(nOutputUnReturnNum == 0) { ret = pVencCxt->pVEncDevice->ResetBitStreamFrame(pVencCxt->pEncoderHandle); if(ret) return -1; } else { loge("flush output buffer failed as caller not return all output buffer to vencoder, nOutputUnReturnNum = %d", nOutputUnReturnNum); } } return ret; } /* online-2-buf & all offline-channel: 1. check in-frame of all channel, if had, continue encode; 2. no need check out-frame; */ static void checkIsReady_online2Buf() { int i = 0; VencContext *pCurVencCxt = NULL; unsigned int bOnlineChannelInFrameIsReady = 0; unsigned int bNeedContinueDoEncode = 0; unsigned int bBSBufIsFull = 0; unsigned int bHadInFrame = 0; unsigned int bHadOutFrame = 0; unsigned int nActiveOnlineChannelNum = 0; unsigned int nActiveOfflineChannelNum = 0; unsigned int bJustHadOnlineActiveChannel = 0; unsigned int bOnlineChannelHadIdleOutFrame = 0; pOnlineCxt->bNoInputFrameFlag = 0; pOnlineCxt->bNoOutputStreamBufFlag = 0; //*check whether need wait for in-frame pthread_mutex_lock(&pOnlineCxt->mInputFrameLock); pthread_mutex_lock(&pOnlineCxt->mOutputStreamLock); for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i]) { pCurVencCxt = pOnlineCxt->pVencCxt[i]; bHadInFrame = 0; bHadOutFrame = 0; if(pCurVencCxt->eState != VENCODER_STATE_EXCUTING) continue; VencGetParameter((VideoEncoder* )pCurVencCxt, VENC_IndexParamBSbufIsFull, &bBSBufIsFull); if(bBSBufIsFull == 0) bHadOutFrame = 1; if(pCurVencCxt->baseConfig.bOnlineChannel == 0) { nActiveOfflineChannelNum++; if(VencGetValidInputBufNum((VideoEncoder*)pCurVencCxt) > 0) bHadInFrame = 1; } else { nActiveOnlineChannelNum++; if (pCurVencCxt->codecType != VENC_CODEC_JPEG) VencGetParameter((VideoEncoder* )pCurVencCxt, VENC_IndexParamCheckOnlineStatus, &bOnlineChannelInFrameIsReady); if(bOnlineChannelInFrameIsReady == 1) bHadInFrame = 1; if(bBSBufIsFull == 0) { bOnlineChannelHadIdleOutFrame = 1; } } if(bHadInFrame == 1 && bHadOutFrame == 1) bNeedContinueDoEncode = 1; logv("bNeedContinueDoEncode = %d, bHadInFrame = %d, bHadOutFrame = %d, i = %d", bNeedContinueDoEncode, bHadInFrame, bHadOutFrame, i); } } //* JustHadOnlineActiveChannel also need wait sem when had no OutFrame; if(nActiveOfflineChannelNum == 0 && nActiveOnlineChannelNum == 1) bJustHadOnlineActiveChannel = 1; if(bJustHadOnlineActiveChannel == 1) { if(0 == bNeedContinueDoEncode) { if(1 == bOnlineChannelHadIdleOutFrame) { bNeedContinueDoEncode = 1; } } } if(bNeedContinueDoEncode == 0) { logv("** need wait for inputframe"); pOnlineCxt->bNoInputFrameFlag = 1; pOnlineCxt->bNoOutputStreamBufFlag = 1; } pthread_mutex_unlock(&pOnlineCxt->mOutputStreamLock); pthread_mutex_unlock(&pOnlineCxt->mInputFrameLock); if(bNeedContinueDoEncode == 0) CdcMessageQueueWaitMessage(pOnlineCxt->mq, 200); return ; } /* online-1-buf: 1. check in-frame of all offline-channel, if had, continue encode; -- (bOfflineChannelHadInFrame = 1) 2. check out-frame of online-channle, if had, continue encode; -- (bOnlineChannelHadOutFrame = 1) 3. if(bOfflineChannelHadInFrame == 0 && bOnlineChannelHadOutFrame == 0), wait for it */ static void checkIsReady_online1Buf() { int i = 0; VencContext *pCurVencCxt = NULL; //*check whether need wait for in-frame unsigned int bOfflineChannelHadInFrame = 0; unsigned int bOnlineChannelHadOutFrame = 0; unsigned int bBSBufIsFull = 0; unsigned int bNeedWaitForMsg = 0; pOnlineCxt->bNoInputFrameFlag = 0; pOnlineCxt->bNoOutputStreamBufFlag = 0; pthread_mutex_lock(&pOnlineCxt->mInputFrameLock); pthread_mutex_lock(&pOnlineCxt->mOutputStreamLock); for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i]) { pCurVencCxt = pOnlineCxt->pVencCxt[i]; if(pCurVencCxt->eState != VENCODER_STATE_EXCUTING) continue; //* check in-frame of offline channel //* check out-frame of online channel if(pCurVencCxt->baseConfig.bOnlineChannel == 0) { if(VencGetValidInputBufNum((VideoEncoder*)pCurVencCxt) > 0) bOfflineChannelHadInFrame = 1; } else { VencGetParameter((VideoEncoder* )pCurVencCxt, VENC_IndexParamBSbufIsFull, &bBSBufIsFull); if(bBSBufIsFull == 0) bOnlineChannelHadOutFrame = 1; } } } if(bOfflineChannelHadInFrame == 0 && bOnlineChannelHadOutFrame == 0) { logv("** need wait for inputframe"); pOnlineCxt->bNoInputFrameFlag = 1; pOnlineCxt->bNoOutputStreamBufFlag = 1; bNeedWaitForMsg = 1; } pthread_mutex_unlock(&pOnlineCxt->mOutputStreamLock); pthread_mutex_unlock(&pOnlineCxt->mInputFrameLock); if(bNeedWaitForMsg == 1) CdcMessageQueueWaitMessage(pOnlineCxt->mq, 200); return ; } #if VENC_SUPPORT_EXT_PARAM #define VE_PARAM_FILE_PATH "/tmp/ve_param_file_path.conf" #define VE_PARAM_XML_NAME "/etc/ve_param_" void ve_param_set_res(VideoEncoder* pVideoEnc, VencParamFromFiles *p_ve_param) { VencContext *pCurVencCxt = (VencContext*)pVideoEnc; pCurVencCxt->baseConfig.nInputWidth = p_ve_param->nInputWidth; pCurVencCxt->baseConfig.nInputHeight = p_ve_param->nInputHeight; pCurVencCxt->baseConfig.nDstWidth = p_ve_param->nDstWidth; pCurVencCxt->baseConfig.nDstHeight = p_ve_param->nDstHeight; } void ve_param_set_pxl_format(VideoEncoder* pVideoEnc, VencParamFromFiles *p_ve_param) { VencContext *pCurVencCxt = (VencContext*)pVideoEnc; pCurVencCxt->baseConfig.eInputFormat = p_ve_param->eInputFormat; pCurVencCxt->baseConfig.eOutputFormat = p_ve_param->eOutputFormat; } static int check_ve_param_file(int is_static, VencContext *pCurVencCxt, int ch_id) { char ve_param_filename[256] = {0}; char ve_param_filename_used[256] = {0}; VencParamFromFiles st_ve_param; XML_Parser parser = NULL; FILE *xml_file = NULL; FILE *path_file = NULL; memset(&st_ve_param, 0, sizeof(VencParamFromFiles)); st_ve_param.is_static = is_static; st_ve_param.pVideoEnc = (VideoEncoder*)pCurVencCxt; st_ve_param.codecType = pCurVencCxt->codecType; path_file = fopen(VE_PARAM_FILE_PATH, "r"); if(path_file) { char line[256] = {0}; int file_size = 0; fseek(path_file, 0, SEEK_END); file_size = ftell(path_file); rewind(path_file); if (file_size > sizeof(line)) { loge("file_size large than %d, please change.", sizeof(line)); fclose(path_file); goto ERROR_FOPEN_XML_FILE; } if (fgets(line, sizeof(line), path_file) != NULL) { if (line[strlen(line) - 1] == '\n') line[strlen(line) - 1] = '\0'; snprintf(ve_param_filename, sizeof(ve_param_filename), "%s%d.xml", line, ch_id); //logd("read xml file path: %s", ve_param_filename); } else { logw("read failed, maybe %s context is null, use %s\n", VE_PARAM_FILE_PATH, VE_PARAM_XML_NAME); snprintf(ve_param_filename, sizeof(ve_param_filename), "%s%d.xml", VE_PARAM_XML_NAME, ch_id); } fclose(path_file); } else { snprintf(ve_param_filename, sizeof(ve_param_filename), "%s%d.xml", VE_PARAM_XML_NAME, ch_id); } if (access(ve_param_filename, F_OK) == 0) { if (is_static) logd("static get param xml file: %s", ve_param_filename); else logd("dynamic get param xml file: %s", ve_param_filename); xml_file = fopen(ve_param_filename, "r"); if(xml_file) { if (ParserCreateAndParse(parser, &st_ve_param, xml_file ) != 0) goto CREATE_ERROR; if (is_static) { logd("static_set_ve_param done!"); } else { char *tmp = strstr(ve_param_filename, ".xml"); strncpy(ve_param_filename_used, ve_param_filename, tmp - ve_param_filename); strcat(ve_param_filename_used, "_used"); strcat(ve_param_filename_used, tmp); rename(ve_param_filename, ve_param_filename_used); logd("dynamic_set_ve_param done! change file name to %s", ve_param_filename_used); } } else { loge("Please push %s.xml", ve_param_filename); goto ERROR_FOPEN_XML_FILE; } } CREATE_ERROR: if (xml_file) fclose(xml_file); ERROR_FOPEN_XML_FILE: return 0; } #endif void* OnlineThreadProcess(void* param) { int i = 0; int ret = 0; VencContext *pCurVencCxt = NULL; VencInputBuffer mInputBuffer; memset(&mInputBuffer, 0, sizeof(VencInputBuffer)); CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); sem_t* pReplySem = NULL; int bHadNoOfflineChannel = 0; int bHadOnlineChannel = 0; int bNeedProcessMsg = 0; int nRealValidChannelNum = 0; int bNeedWaitForInputFrame = 0; int bThreadExcutingState = 0; int bBSBufIsFull = 0; int bNeedWaitForOutputBuf = 0; int bOfflineChannelHadNoInFrame = 0; int tmp_cnt = 0; int maxLoopEncodeCnt = 10; logd("online thread start"); prctl(PR_SET_NAME, (unsigned long)"OnlineVenc", 0, 0, 0); while(1) { //* process message tmp_cnt++; if(CdcMessageQueueTryGetMessage(pOnlineCxt->mq, &msg, 0) == 0) { pCurVencCxt = (VencContext *)msg.params[1]; if(msg.messageId == VENCODER_CMD_SET_STATE_INIT) { pCurVencCxt->eState = VENCODER_STATE_INITED; } else if(msg.messageId == VENCODER_CMD_SET_STATE_EXECUT) { //* disable "reset the whole ve when call resetVe()" if(pCurVencCxt->veOpsS && pCurVencCxt->pVeOpsSelf && pCurVencCxt->baseConfig.bOnlineChannel && pCurVencCxt->bEnableResetWholeVE == 0) CdcVeSetOnlineChannel(pCurVencCxt->veOpsS, pCurVencCxt->pVeOpsSelf, 1); pCurVencCxt->eState = VENCODER_STATE_EXCUTING; if(pCurVencCxt->baseConfig.bOnlineChannel == 1) bHadOnlineChannel = 1; } else if(msg.messageId == VENCODER_CMD_SET_STATE_PAUSE) { pCurVencCxt->eState = VENCODER_STATE_PAUSE; } else if(msg.messageId == VENCODER_CMD_RESET) { doReset(pCurVencCxt); } else if(msg.messageId == VENCODER_CMD_FLUSH) { VencFlushType eFlushType = (VencFlushType)msg.params[2]; doFlush(pCurVencCxt, eFlushType); } else if(msg.messageId == VENCODER_CMD_EXIT) { for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i] == pCurVencCxt) { if(pCurVencCxt->baseConfig.bOnlineChannel == 1) pOnlineCxt->eOnlineBufNum = Had_No_Online_Channel; pOnlineCxt->pVencCxt[i] = NULL; pOnlineCxt->nValidChannelNum--; break; } } } else if(msg.messageId == VENCODER_CMD_InputFrameAvailable) { pOnlineCxt->bNoInputFrameFlag = 0; } else if(msg.messageId == VENCODER_CMD_OutputStreamAvailable) { pOnlineCxt->bNoOutputStreamBufFlag = 0; } pReplySem = (sem_t*)msg.params[0]; logv("pReplySem = %p, pCurVencCxt = %p, cmd = %d, cnt = %d", pReplySem, pCurVencCxt, msg.messageId, tmp_cnt); if(pReplySem) sem_post(pReplySem); } nRealValidChannelNum = 0; bThreadExcutingState = 0; for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->pVencCxt[i]) nRealValidChannelNum++; if(pOnlineCxt->pVencCxt[i] && pOnlineCxt->pVencCxt[i]->eState == VENCODER_STATE_EXCUTING) bThreadExcutingState = 1; } logv("nRealValidChannelNum = %d", nRealValidChannelNum); if(nRealValidChannelNum <= 0) { logd("exit the loop process, nRealValidChannelNum = %d",nRealValidChannelNum); break; } if(bThreadExcutingState == 1) { //* do encode frame of offline-channel first; for(i = 0; i < MAX_VENCODER_CHANNEL_NUM; i++) { if(pOnlineCxt->nOnlineChannelIndex == i) continue; if(pOnlineCxt->pVencCxt[i]) { pCurVencCxt = pOnlineCxt->pVencCxt[i]; #if VENC_SUPPORT_EXT_PARAM check_ve_param_file(VE_PARAM_DYNAMIC, pCurVencCxt, i); #endif logv("pCurVencCxt = %p, i = %d", pCurVencCxt, i); if(pCurVencCxt->eState == VENCODER_STATE_EXCUTING) { if(pOnlineCxt->eOnlineBufNum == Had_No_Online_Channel) { int64_t start_t = getCurrentTime(); ret = encodeOneFrame((VideoEncoder*)pCurVencCxt); int64_t end_t = getCurrentTime(); if (ret == VENC_RESULT_OK) logv("offline[%d] encoder, ret = %d, time = %lld ms, cnt = %d",i, ret, (end_t - start_t)/1000, tmp_cnt); } else { //* encode all in-frame of every offline channel when had online channel ret = VENC_RESULT_OK; maxLoopEncodeCnt = 10; while(ret == VENC_RESULT_OK) { int64_t start_t = getCurrentTime(); ret = encodeOneFrame((VideoEncoder*)pCurVencCxt); int64_t end_t = getCurrentTime(); if (ret == VENC_RESULT_OK) logv("offline[%d] encoder, ret = %d, time = %lld ms, cnt = %d",i, ret, (end_t - start_t)/1000, tmp_cnt); maxLoopEncodeCnt--; if(maxLoopEncodeCnt <= 0) { logw("loop do encode cnt exceed maxCnt[10]"); break; } } } } } } //* do encode frame of online-channel; if(pOnlineCxt->nOnlineChannelIndex >= 0) { pCurVencCxt = pOnlineCxt->pVencCxt[pOnlineCxt->nOnlineChannelIndex]; if(pCurVencCxt) { if(pCurVencCxt->eState == VENCODER_STATE_EXCUTING) { int64_t start_t = getCurrentTime(); ret = encodeOneFrame((VideoEncoder*)pCurVencCxt); int64_t end_t = getCurrentTime(); if (ret == 0) { logv("online[%d] encoder, ret = %d, time = %lld ms, cnt = %d, ", pOnlineCxt->nOnlineChannelIndex, ret, (end_t - start_t)/1000, tmp_cnt); } } } } logv("pOnlineCxt->eOnlineBufNum = %d", pOnlineCxt->eOnlineBufNum); if(pOnlineCxt->eOnlineBufNum == Had_Online_Channel_One_Buf) checkIsReady_online1Buf(); else if(pOnlineCxt->eOnlineBufNum == Had_Online_Channel_Two_Buf || pOnlineCxt->eOnlineBufNum == Had_No_Online_Channel) checkIsReady_online2Buf(); else loge("eOnlineBufNum[%d] is error", pOnlineCxt->eOnlineBufNum); } else { CdcMessageQueueWaitMessage(pOnlineCxt->mq, 200); } } logd("exit the thread"); return 0; } void* OfflineThreadProcess(void* param) { int ret = 0; VencContext *pVencCxt = (VencContext *)param; sem_t* pReplySem = NULL; VencInputBuffer mInputBuffer; memset(&mInputBuffer, 0, sizeof(VencInputBuffer)); CdcMessage msg; memset(&msg, 0, sizeof(CdcMessage)); int bExitFlag = 0; int bNeedWaitMsg = 0; logd("offline thread start"); char strThreadName[32]; sprintf(strThreadName, "OfflineVencChn%d", pVencCxt->nChannelId); prctl(PR_SET_NAME, (unsigned long)strThreadName, 0, 0, 0); while(1) { //* process message if(CdcMessageQueueTryGetMessage(pVencCxt->mq, &msg, 0) == 0) { if(msg.messageId == VENCODER_CMD_SET_STATE_INIT) pVencCxt->eState = VENCODER_STATE_INITED; else if(msg.messageId == VENCODER_CMD_SET_STATE_EXECUT) pVencCxt->eState = VENCODER_STATE_EXCUTING; else if(msg.messageId == VENCODER_CMD_SET_STATE_PAUSE) pVencCxt->eState = VENCODER_STATE_PAUSE; else if(msg.messageId == VENCODER_CMD_RESET) { doReset(pVencCxt); } else if(msg.messageId == VENCODER_CMD_FLUSH) { VencFlushType eFlushType = (VencFlushType)msg.params[2]; doFlush(pVencCxt, eFlushType); } else if(msg.messageId == VENCODER_CMD_EXIT) { bExitFlag = 1; } else if(msg.messageId == VENCODER_CMD_InputFrameAvailable) { pVencCxt->bNoInputFrameFlag = 0; } else if(msg.messageId == VENCODER_CMD_OutputStreamAvailable) { pVencCxt->bNoOutputStreamBufFlag = 0; } pReplySem = (sem_t*)msg.params[0]; logv("pReplySem = %p, cmd = %d",pReplySem, msg.messageId); if(pReplySem) sem_post(pReplySem); } if(bExitFlag == 1) { logd("exit the loop process"); break; } //* do encode frame if(pVencCxt->eState == VENCODER_STATE_EXCUTING) { #if VENC_SUPPORT_EXT_PARAM check_ve_param_file(VE_PARAM_DYNAMIC, pVencCxt, pVencCxt->nChannelId); #endif ret = encodeOneFrame((VideoEncoder*)pVencCxt); if(ret == VENC_RESULT_NO_FRAME_BUFFER) { bNeedWaitMsg = 0; pthread_mutex_lock(&pVencCxt->mInputFrameLock); if(VencFbmGetValidBufferNum(pVencCxt->pFBM) <= 0) { pVencCxt->bNoInputFrameFlag = 1; bNeedWaitMsg = 1; } pthread_mutex_unlock(&pVencCxt->mInputFrameLock); if(bNeedWaitMsg == 1) CdcMessageQueueWaitMessage(pVencCxt->mq, 200); continue; } else if(ret == VENC_RESULT_BITSTREAM_IS_FULL) { int bBSBufIsFull = 0; bNeedWaitMsg = 0; pthread_mutex_lock(&pVencCxt->mOutputStreamLock); VencGetParameter((VideoEncoder* )pVencCxt, VENC_IndexParamBSbufIsFull, &bBSBufIsFull); if(bBSBufIsFull == 1) { pVencCxt->bNoOutputStreamBufFlag = 1; bNeedWaitMsg = 1; } pthread_mutex_unlock(&pVencCxt->mOutputStreamLock); if(bNeedWaitMsg == 1) CdcMessageQueueWaitMessage(pVencCxt->mq, 200); continue; } //if (ret == 0) // logv("encoder, ret = %d, time = %lld ms",ret, (end_t - start_t)/1000); } else { CdcMessageQueueWaitMessage(pVencCxt->mq, 200); } } logd("exit the thread"); return 0; } #ifdef __cplusplus } #endif /* __cplusplus */