/****************************************************************************** Copyright (C), 2018-2020, Allwinner Tech. Co., Ltd. ****************************************************************************** File Name : VideoEIS_Component.c Version : Initial Draft Author : Allwinner PDC-PD5 Team Created : 2018/04/20 Last Modified : Description : EIS mpp component implement Function List : History : ******************************************************************************/ #define LOG_TAG "VideoEIS_Component" #include //ref platform headers #include #include #include #include #include #include #include #include "plat_defines.h" #include "plat_errno.h" #include "plat_math.h" #include "plat_type.h" #include "cdx_list.h" #include "SystemBase.h" #include #include "mm_comm_eis.h" #include "mm_comm_video.h" #include "mm_comm_vi.h" #include "mm_common.h" #include "ComponentCommon.h" #include "media_common.h" #include "mm_component.h" #include "tmessage.h" #include "tsemaphore.h" #include "vencoder.h" #include "ion_memmanager.h" #include "VideoEIS_Component.h" #include "video_buffer_manager.h" #include "utils/ring_buffer.h" #include "utils/iio_utils.h" #include "utils/generic_buffer.h" #include "algo/include/EIS_lib.h" typedef struct VideoEisPrivAttr { float fGyroAxScaleFactor; float fGyroAyScaleFactor; float fGyroAzScaleFactor; float fGyroVxScaleFactor; float fGyroVyScaleFactor; float fGyroVzScaleFactor; } VIDEO_EIS_PRIVATTR; typedef struct VideoEisDataType { COMP_STATETYPE state; pthread_mutex_t mStateLock; COMP_CALLBACKTYPE* pCallbacks; void* pAppData; COMP_HANDLETYPE hSelf; COMP_PORT_PARAM_TYPE sPortParam; COMP_PARAM_PORTDEFINITIONTYPE sPortDef[EIS_CHN_MAX_PORTS]; COMP_INTERNAL_TUNNELINFOTYPE sPortTunnelInfo[EIS_CHN_MAX_PORTS]; COMP_PARAM_BUFFERSUPPLIERTYPE sPortBufSupplier[EIS_CHN_MAX_PORTS]; /* TRUE: tunnel mode; FALSE: non-tunnel mode. */ bool bInputPortTunnelFlag; bool bOutputPortTunnelFlag; MPP_CHN_S mMppChnInfo; pthread_t mEISTrd; message_queue_t cmd_queue; /* Gyro informations */ pthread_t mGyroTrd; bool bGyroRunFlag; bool bHasGyroDev; struct gyro_device_attr mGyroAttr; struct ring_buffer* GryoRingBufHd; unsigned int iGVSyncPktId; struct gyro_instance *pGyroIns; /* Video buffer informations */ bool bWaitingInputFrmFlag; VideoBufferManager *pInputBufMgr; pthread_mutex_t mInputFrmLock; bool bWaitingOutFrmFlag; cdx_sem_t mSemWaitOutFrame; pthread_mutex_t mOutFrmListLock; struct list_head mOutIdleList; struct list_head mOutValidList; struct list_head mOutUsedList; int iOutFrmCnt; int iOutFrmIdleCnt; /* Begin from the beginning of first line exposure, * end to the beginning of last line exposure. */ int iVideoLineTime; /* Unit: ms */ EISE_FrameData* pstEISPkt; unsigned long long iEISPktIdx; unsigned long long mEisPktMap; // We use map to manage EIS packets EISE_FrameData* pLastUsedEISPkt; uint64_t dLastInputFrmPts; EIS_ATTR_S mEISAttr; VIDEO_EIS_PRIVATTR mEisPrivAttr; /* Hardware EIS attributions */ int iEisHwFreq; EISE_HANDLE mEisHd; EISE_CFG_PARA mEisCfg; pthread_mutex_t mEISAttrLock; uint64_t dEisGetInputFrmCnt; cdx_sem_t mAllFrameRelSem; volatile int mWaitAllFrameReleaseFlag; bool bEnableFlag; pthread_mutex_t mEISLock; bool bByPassMode; char *pBPDataSavePath; FILE *pVideoPtsFd; FILE *pGyroPtsDataFd; FILE *pVideoDataFd; int iCacheBufferNum; bool bStoreFrame; int mStoreFrameCount; char mDbgStoreFrameFilePath[EIS_MAXPATHSIZE]; } VIDEOEISDATATYPE; #define LOCK_DEBUG //#define GYRO_DATA_SAVE_DEBUG //#define PROC_TIME_TEST #define TIME_INIT_START_END(x) struct timeval start_##x; \ struct timeval end_##x; \ float DiffTime_##x; #define TIME_GET_START(x) (gettimeofday(&start_##x, NULL)) #define TIME_GET_END(x) (gettimeofday(&end_##x, NULL)); \ (DiffTime_##x = \ (((end_##x.tv_sec + end_##x.tv_usec * 1e-6) - \ (start_##x.tv_sec + start_##x.tv_usec * 1e-6)) * 1000)) #define TIME_PRINT_DIFF(x) (DiffTime_##x) static void *EIS_CompGyroThread(void *pThreadData); static void *EIS_CompStabThread(void *pThreadData); ERRORTYPE DoVideoEisGetTunnelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_INTERNAL_TUNNELINFOTYPE *pTunnelInfo) { VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; int i; for(i = 0; i < EIS_CHN_MAX_PORTS; i++) { if(pVideoEISData->sPortBufSupplier[i].nPortIndex == pTunnelInfo->nPortIndex) { memcpy(pTunnelInfo, &pVideoEISData->sPortTunnelInfo[i], sizeof(COMP_INTERNAL_TUNNELINFOTYPE)); break; } } if(i == EIS_CHN_MAX_PORTS) { aloge("No such port index[%d] in EIS[%d].", pTunnelInfo->nPortIndex, pVideoEISData->mMppChnInfo.mChnId); eError = ERR_EIS_INVALID_PARA; } return eError; } static void DoVideoEisStoreProcessedFrm(VIDEOEISDATATYPE* pVideoEISData, VIDEO_FRAME_INFO_S* SFrame) { char strPixFmt[16]; if(MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420==SFrame->VFrame.mPixelFormat || MM_PIXEL_FORMAT_AW_NV21S==SFrame->VFrame.mPixelFormat) strcpy(strPixFmt, "nv21"); else if(MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420 == SFrame->VFrame.mPixelFormat) strcpy(strPixFmt, "nv12"); else strcpy(strPixFmt, "unknown"); int nPos = strlen(pVideoEISData->mDbgStoreFrameFilePath); snprintf(pVideoEISData->mDbgStoreFrameFilePath+nPos, EIS_MAXPATHSIZE-nPos, "/EisChn[%d]Pic[%d].%s", pVideoEISData->mMppChnInfo.mChnId, pVideoEISData->mStoreFrameCount++, strPixFmt); FILE *dbgFp = fopen(pVideoEISData->mDbgStoreFrameFilePath, "wb"); VideoFrameBufferSizeInfo FrameSizeInfo; getVideoFrameBufferSizeInfo(SFrame, &FrameSizeInfo); int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize}; for(int i = 0; i < 3; i++) { if(SFrame->VFrame.mpVirAddr[i] != NULL) { fwrite(SFrame->VFrame.mpVirAddr[i], 1, yuvSize[i], dbgFp); alogd("virAddr[%d]=[%p], length=[%d]", i, SFrame->VFrame.mpVirAddr[i], yuvSize[i]); } } fclose(dbgFp); alogd("Store EIS frame in file[%s]", pVideoEISData->mDbgStoreFrameFilePath); } ERRORTYPE DoVideoEisGetData(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT EIS_PARAMS_S *pstParams, PARAM_IN int nMilliSec) { ERRORTYPE eError = SUCCESS; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (COMP_StateIdle != pVideoEISData->state && COMP_StateExecuting != pVideoEISData->state) { alogw("call getStream in wrong state[0x%x]", pVideoEISData->state); return ERR_VI_NOT_PERM; } int ret; /* not support get data in Tunnel mode for app */ if (TRUE == pVideoEISData->bOutputPortTunnelFlag) { aloge("You are in output bind mode, do not get data in yourself."); return ERR_VI_NOT_PERM; } VIDEO_FRAME_INFO_S *pstFrameInfo = pstParams->pstFrameInfo; VideoFrameListInfo *pVFrmListTmp = NULL; _TryToGetFrame: pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); if (!list_empty(&pVideoEISData->mOutValidList)) { pVFrmListTmp = list_first_entry(&pVideoEISData->mOutValidList, VideoFrameListInfo, mList); memcpy(pstFrameInfo, &pVFrmListTmp->mFrame, sizeof(VIDEO_FRAME_INFO_S)); pstFrameInfo->VFrame.mOffsetTop = 0; pstFrameInfo->VFrame.mOffsetBottom = pstFrameInfo->VFrame.mHeight; pstFrameInfo->VFrame.mOffsetLeft = 0; pstFrameInfo->VFrame.mOffsetRight = pstFrameInfo->VFrame.mWidth; if(pVideoEISData->bStoreFrame) { DoVideoEisStoreProcessedFrm(pVideoEISData, pstFrameInfo); pVideoEISData->bStoreFrame = FALSE; } eError = SUCCESS; list_move_tail(&pVFrmListTmp->mList, &pVideoEISData->mOutUsedList); pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); } else { pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); if(0 == nMilliSec) { eError = ERR_EIS_BUF_EMPTY; } else if(nMilliSec < 0) { pVideoEISData->bWaitingOutFrmFlag = TRUE; cdx_sem_down(&pVideoEISData->mSemWaitOutFrame); pVideoEISData->bWaitingOutFrmFlag = FALSE; goto _TryToGetFrame; } else { pVideoEISData->bWaitingOutFrmFlag = TRUE; ret = cdx_sem_down_timedwait(&pVideoEISData->mSemWaitOutFrame, nMilliSec); if(0 == ret) { pVideoEISData->bWaitingOutFrmFlag = FALSE; goto _TryToGetFrame; } else { aloge("Fatal error! EIS[%d] pthread cond wait timeout ret[%d]", pVideoEISData->mMppChnInfo.mChnId, ret); eError = ERR_EIS_BUF_EMPTY; pVideoEISData->bWaitingOutFrmFlag = FALSE; } } } return eError; } ERRORTYPE DoVideoEisReleaseData(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN EIS_PARAMS_S *pstParams) { VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (COMP_StateIdle != pVideoEISData->state && COMP_StateExecuting != pVideoEISData->state) { alogw("Call getStream in wrong state[0x%x]", pVideoEISData->state); return ERR_EIS_INVALIDSTATE; } if (TRUE == pVideoEISData->bOutputPortTunnelFlag) { /* Tunnel mode */ aloge("You are in output bind mode, do not get data in yourself."); return ERR_EIS_NOT_PERM; } int iEisChn = pstParams->mChn; bool bFindFlag = 0; VIDEO_FRAME_INFO_S *pstFrameInfo = pstParams->pstFrameInfo; VideoFrameListInfo *pVFrmList; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); list_for_each_entry(pVFrmList, &pVideoEISData->mOutUsedList, mList) { if (pVFrmList->mFrame.mId == pstFrameInfo->mId || pVFrmList->mFrame.VFrame.mpVirAddr[0] == pstFrameInfo->VFrame.mpVirAddr[0]) { bFindFlag = 1; break; } } if (bFindFlag) { list_move_tail(&pVFrmList->mList, &pVideoEISData->mOutIdleList); pVideoEISData->iOutFrmIdleCnt++; } else { aloge("No such video frame Id[%d] is using, please check it.", pstFrameInfo->mId); pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); return ERR_EIS_INVALID_PARA; } pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); return SUCCESS; } ERRORTYPE DoVideoEisStoreFrameOpr(PARAM_IN COMP_HANDLETYPE hComponent, const char* pDirPath) { VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoEISData->bOutputPortTunnelFlag) { alogw("in non-tunnel mode, you should store frame by your self, we don't do it\n"); return ERR_EIS_NOT_SUPPORT; } message_t msg; InitMessage(&msg); msg.command = EisComp_StoreFrame; msg.mpData = (void*)pDirPath; msg.mDataSize = strlen(pDirPath)+1; putMessageWithData(&pVideoEISData->cmd_queue, &msg); return SUCCESS; } ERRORTYPE VideoEISSendCommand(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_COMMANDTYPE Cmd, PARAM_IN unsigned int nParam1, PARAM_IN void *pCmdData) { VIDEOEISDATATYPE *pVideoEISData; CompInternalMsgType eCmd; ERRORTYPE eError = SUCCESS; message_t msg; alogv("VideoEISSendCommand: %d", Cmd); pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoEISData) { eError = ERR_EIS_SYS_NOTREADY; goto ENotReady; } if (pVideoEISData->state == COMP_StateInvalid) { eError = ERR_EIS_NOT_PERM; goto ENotReady; } switch (Cmd) { case COMP_CommandStateSet: eCmd = SetState; break; case COMP_CommandFlush: eCmd = Flush; break; default: alogw("impossible comp_command[0x%x]", Cmd); eCmd = -1; eError = ERR_EIS_NOT_SUPPORT; goto ENotSupport; break; } msg.command = eCmd; msg.para0 = nParam1; put_message(&pVideoEISData->cmd_queue, &msg); ENotSupport: ENotReady: return eError; } ERRORTYPE VideoEISGetState(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT COMP_STATETYPE *pState) { ERRORTYPE eError = SUCCESS; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); *pState = pVideoEISData->state; return eError; } ERRORTYPE VideoEISSetCallbacks(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_CALLBACKTYPE *pCallbacks, PARAM_IN void *pAppData) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoEISData || !pCallbacks || !pAppData) { eError = ERR_VI_INVALID_PARA; goto COMP_CONF_CMD_FAIL; } pVideoEISData->pCallbacks = pCallbacks; pVideoEISData->pAppData = pAppData; COMP_CONF_CMD_FAIL: return eError; } ERRORTYPE DoVideoEisChnConfigOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_ATTR_S *pEisAttr, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); switch (eConfOpr) { case EIS_CHN_CONF_SET: { if (pEisAttr) { memcpy(&pVideoEISData->mEISAttr, pEisAttr, sizeof(EIS_ATTR_S)); pVideoEISData->mGyroAttr.sample_freq = pEisAttr->iGyroFreq; pVideoEISData->mGyroAttr.axi_num = pEisAttr->iGyroAxiNum; } } break; case EIS_CHN_CONF_GET: { if (pEisAttr) memcpy(pEisAttr, &pVideoEISData->mEISAttr, sizeof(EIS_ATTR_S)); else { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; } } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } return eError; } ERRORTYPE DoSetEisChnAlgoModeOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_ALGO_MODE *pEisAttr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (NULL == pEisAttr) { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; goto ENullPtr; } pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateIdle && pVideoEISData->state != COMP_StateLoaded) { aloge("Send frame when EIS component state[0x%x].", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; goto EState; } EState: pthread_mutex_unlock(&pVideoEISData->mStateLock); ENullPtr: return eError; } ERRORTYPE DoSetEisChnVFmtOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_VIDEO_FMT_ATTR_S *pEisAttr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (NULL == pEisAttr) { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; goto ENullPtr; } pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateIdle && pVideoEISData->state != COMP_StateLoaded) { aloge("Send frame when EIS component state[0x%x].", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; goto EState; } pVideoEISData->mEISAttr.iVideoInWidth = pEisAttr->iVideoInWidth; pVideoEISData->mEISAttr.iVideoInWidthStride = pEisAttr->iVideoInWidthStride; pVideoEISData->mEISAttr.iVideoInHeight = pEisAttr->iVideoInHeight; pVideoEISData->mEISAttr.iVideoInHeightStride = pEisAttr->iVideoInHeightStride; pVideoEISData->mEISAttr.iVideoOutWidth = pEisAttr->iVideoOutWidth; pVideoEISData->mEISAttr.iVideoOutHeight = pEisAttr->iVideoOutHeight; pVideoEISData->mEISAttr.eVideoFmt = pEisAttr->eVideoFmt; EState: pthread_mutex_unlock(&pVideoEISData->mStateLock); ENullPtr: return eError; } ERRORTYPE DoSetEisChnDataProcOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_DATA_PROC_ATTR_S *pEisAttr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (NULL == pEisAttr) { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; goto ENullPtr; } pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateIdle && pVideoEISData->state != COMP_StateLoaded) { aloge("Send frame when EIS component state[0x%x].", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; goto EState; } pVideoEISData->mEISAttr.bRetInFrmFast = pEisAttr->bRetInFrmFast; pVideoEISData->mEISAttr.bHorizFlip = pEisAttr->bHorizFlip; pVideoEISData->mEISAttr.bVerticalFlip = pEisAttr->bVerticalFlip; pVideoEISData->mEISAttr.iInputBufNum = pEisAttr->iInputBufNum; pVideoEISData->mEISAttr.iOutputBufBum = pEisAttr->iOutputBufBum; pVideoEISData->mEISAttr.iDelayTimeMs = pEisAttr->iDelayTimeMs; pVideoEISData->mEISAttr.iEisFilterWidth = pEisAttr->iEisFilterWidth; pVideoEISData->mEISAttr.iSyncErrTolerance = pEisAttr->iSyncErrTolerance; EState: pthread_mutex_unlock(&pVideoEISData->mStateLock); ENullPtr: return eError; } ERRORTYPE DoSetEisChnGyroOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_GYRO_DATA_ATTR_S *pEisAttr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (NULL == pEisAttr) { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; goto ENullPtr; } pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateIdle && pVideoEISData->state != COMP_StateLoaded) { aloge("Send frame when EIS component state[0x%x].", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; goto EState; } pVideoEISData->mEISAttr.iGyroFreq = pEisAttr->iGyroFreq; pVideoEISData->mEISAttr.iGyroPoolSize = pEisAttr->iGyroPoolSize; pVideoEISData->mEISAttr.iGyroAxiNum = pEisAttr->iGyroAxiNum; EState: pthread_mutex_unlock(&pVideoEISData->mStateLock); ENullPtr: return eError; } ERRORTYPE DoSetEisChnKmatOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT EIS_KMAT_S *pEisAttr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (NULL == pEisAttr) { aloge("You input a NULL pointer to store EIS attribution, fix it."); eError = ERR_EIS_INVALID_NULL_PTR; goto ENullPtr; } pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateIdle && pVideoEISData->state != COMP_StateLoaded) { aloge("Send frame when EIS component state[0x%x].", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; goto EState; } pVideoEISData->mEISAttr.bUseKmat = 1; pVideoEISData->mEISAttr.stEisKmat = *pEisAttr; EState: pthread_mutex_unlock(&pVideoEISData->mStateLock); ENullPtr: return eError; } ERRORTYPE DoVideoEisMPPChannelInfoOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN MPP_CHN_S *pstInfo, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); switch (eConfOpr) { case EIS_CHN_CONF_SET: { copy_MPP_CHN_S(&pVideoEISData->mMppChnInfo, pstInfo); } break; case EIS_CHN_CONF_GET: { copy_MPP_CHN_S(pstInfo, &pVideoEISData->mMppChnInfo); } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } return eError; } ERRORTYPE _EisEnableGyroDeviceMulElem(VIDEOEISDATATYPE *pVideoEISData, int iEnableFlag) { ERRORTYPE eError = SUCCESS; int iRet = 0; if (iEnableFlag) { if (!pVideoEISData->mEISAttr.bSimuOffline) { /* Online mode, then create and open the gyro device. */ pVideoEISData->pGyroIns = create_gyro_inst(); if (NULL == pVideoEISData->pGyroIns) { aloge("Create gyro instance failed."); eError = ERR_EIS_NOMEM; goto ECrtIns; } iRet = gyro_ins_open(pVideoEISData->pGyroIns, &pVideoEISData->mGyroAttr); if (0 != iRet) { aloge("FFFFFFatal error, open gyro instance failed, we will use \"zero\" datas as valid gyro datas."); pVideoEISData->bHasGyroDev = 0; pVideoEISData->GryoRingBufHd = ring_buffer_create(sizeof(EIS_GYRO_PACKET_S), pVideoEISData->mEISAttr.iGyroPoolSize, RB_FL_NONE); if (NULL == pVideoEISData->GryoRingBufHd) { aloge("Create ring buffer for gyro buffers failed."); eError = ERR_EIS_NOMEM; goto EOpenIns; } } else { pVideoEISData->bHasGyroDev = 1; pVideoEISData->GryoRingBufHd = gyro_ins_get_rbhdl(pVideoEISData->pGyroIns); } if (pVideoEISData->mEISAttr.eEisAlgoMode == EIS_ALGO_MODE_BP) pVideoEISData->bByPassMode = 1; if (pVideoEISData->bByPassMode) { pVideoEISData->bGyroRunFlag = 1; if (pthread_create(&pVideoEISData->mGyroTrd, NULL, EIS_CompGyroThread, pVideoEISData)) { aloge("create EIS_CompGyroThread failed!"); eError = ERR_EIS_FAILED_NOTENABLE; pVideoEISData->bGyroRunFlag = 0; goto ECrtThread; } } } else { /* Offline simulation mode, just create ring_buffer module. */ pVideoEISData->GryoRingBufHd = ring_buffer_create(sizeof(EIS_GYRO_PACKET_S), pVideoEISData->mEISAttr.iGyroPoolSize, RB_FL_NONE); if (NULL == pVideoEISData->GryoRingBufHd) { aloge("Create ring buffer for gyro buffers failed."); eError = ERR_EIS_NOMEM; goto ECrtBuffer; } } } else { if (!pVideoEISData->mEISAttr.bSimuOffline) { /* Close and wait gyro read thread exit. */ if (pVideoEISData->pGyroIns) { if (pVideoEISData->bByPassMode) { pVideoEISData->bGyroRunFlag = 0; pthread_join(pVideoEISData->mGyroTrd, NULL); pVideoEISData->mGyroTrd = 0; } /* If we got no gyro device, then we should destroy ring buffer by ourselves. */ if (!pVideoEISData->bHasGyroDev && pVideoEISData->GryoRingBufHd) ring_buffer_destroy(pVideoEISData->GryoRingBufHd); gyro_ins_close(pVideoEISData->pGyroIns); destory_gyro_inst(pVideoEISData->pGyroIns); } else { aloge("You have not enable gyro device yet."); eError = ERR_EIS_NOT_PERM; } } else { /* Destroy ring buffers and close mpu devices */ ring_buffer_destroy(pVideoEISData->GryoRingBufHd); } pVideoEISData->GryoRingBufHd = NULL; } return eError; ECrtThread: gyro_ins_close(pVideoEISData->pGyroIns); EOpenIns: pVideoEISData->GryoRingBufHd = NULL; destory_gyro_inst(pVideoEISData->pGyroIns); ECrtIns: ECrtBuffer: return eError; } ERRORTYPE DoVideoEisChnEnableOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN int* iEnableFlag, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoEISData->mEISLock); switch (eConfOpr) { case EIS_CHN_CONF_SET: { /* Only when [old_val=0,new_val=1] and [old_val=1,new_val=0], we will do real operation invoke, * else [old_val=0,new_val=0] and [old_val=0,new_val=0], just return. */ if (*iEnableFlag + pVideoEISData->bEnableFlag == 1) { eError = _EisEnableGyroDeviceMulElem(pVideoEISData, *iEnableFlag); if (eError != SUCCESS) { aloge("Do enable or disable Gyro device failed. ret 0x%x.", eError); goto EEnable; } pVideoEISData->bEnableFlag = *iEnableFlag; } else alogw("EIS[%d] has already been enabled or disabled.", pVideoEISData->mMppChnInfo.mChnId); } break; case EIS_CHN_CONF_GET: { *iEnableFlag = pVideoEISData->bEnableFlag; } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } EEnable: pthread_mutex_unlock(&pVideoEISData->mEISLock); return eError; } ERRORTYPE DoVideoEisFreqOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN int* iFreqVal, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoEISData->mEISLock); switch (eConfOpr) { case EIS_CHN_CONF_SET: { pVideoEISData->iEisHwFreq = *iFreqVal; } break; case EIS_CHN_CONF_GET: { *iFreqVal = pVideoEISData->iEisHwFreq; } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } EEnable: pthread_mutex_unlock(&pVideoEISData->mEISLock); return eError; } ERRORTYPE DoVideoEisPortDefinitionOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEisData; ERRORTYPE eError = SUCCESS; int i; pVideoEisData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); for(i = 0; i < EIS_CHN_MAX_PORTS; i++) { if (pPortDef->nPortIndex == pVideoEisData->sPortDef[i].nPortIndex) break; } if (i == EIS_CHN_MAX_PORTS) { eError = ERR_EIS_INVALID_PARA; } else { switch (eConfOpr) { case EIS_CHN_CONF_SET: { memcpy(&pVideoEisData->sPortDef[i], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE)); } break; case EIS_CHN_CONF_GET: { memcpy(pPortDef, &pVideoEisData->sPortDef[i], sizeof(COMP_PARAM_PORTDEFINITIONTYPE)); } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } } return eError; } ERRORTYPE DoVideoEisCompBufferSupplierOpr(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier, PARAM_IN EIS_CONF_OPR_E eConfOpr) { VIDEOEISDATATYPE *pVideoEisData; ERRORTYPE eError = SUCCESS; int i; pVideoEisData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); for(i = 0; i < EIS_CHN_MAX_PORTS; i++) { if(pVideoEisData->sPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) break; } if (i == EIS_CHN_MAX_PORTS) { eError = ERR_EIS_INVALID_PARA; } else { switch (eConfOpr) { case EIS_CHN_CONF_SET: { memcpy(&pVideoEisData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE)); } break; case EIS_CHN_CONF_GET: { memcpy(pPortBufSupplier, &pVideoEisData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE)); } break; default: { aloge("Wrong config operation[%d].", eConfOpr); eError = ERR_EIS_NOT_SUPPORT; } break; } } return eError; } ERRORTYPE VideoEISGetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex, PARAM_IN void *pComponentConfigStructure) { // VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; switch (nIndex) { case COMP_IndexVendorEisChnAttr: { eError = DoVideoEisChnConfigOpr(hComponent, (EIS_ATTR_S*)pComponentConfigStructure, EIS_CHN_CONF_GET); } break; case COMP_IndexVendorMPPChannelInfo: { eError = DoVideoEisMPPChannelInfoOpr(hComponent, (MPP_CHN_S *)pComponentConfigStructure, EIS_CHN_CONF_GET); } break; case COMP_IndexVendorEisEnable: { eError = DoVideoEisChnEnableOpr(hComponent, (int*)pComponentConfigStructure, EIS_CHN_CONF_GET); } break; case COMP_IndexVendorEisGetData: { EIS_PARAMS_S *pData = (EIS_PARAMS_S *)pComponentConfigStructure; eError = DoVideoEisGetData(hComponent, pData, pData->s32MilliSec); } break; case COMP_IndexVendorTunnelInfo: { eError = DoVideoEisGetTunnelInfo(hComponent, (COMP_INTERNAL_TUNNELINFOTYPE *)pComponentConfigStructure); } break; case COMP_IndexParamPortDefinition: { eError = DoVideoEisPortDefinitionOpr(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure, EIS_CHN_CONF_GET); } break; case COMP_IndexParamCompBufferSupplier: { eError = DoVideoEisCompBufferSupplierOpr(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure, EIS_CHN_CONF_GET); } break; default: { aloge("fatal error! unknown getConfig Index[0x%x]", nIndex); eError = ERR_VI_NOT_SUPPORT; } break; } return eError; } ERRORTYPE VideoEISSetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex, PARAM_IN void *pComponentConfigStructure) { // VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; switch (nIndex) { case COMP_IndexVendorEisChnAttr: { eError = DoVideoEisChnConfigOpr(hComponent, (EIS_ATTR_S*)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; case COMP_IndexVendorEisAlgoModeAttr: { eError = DoSetEisChnAlgoModeOpr(hComponent, (EIS_ALGO_MODE*)pComponentConfigStructure); } break; case COMP_IndexVendorEisVFmtAttr: { eError = DoSetEisChnVFmtOpr(hComponent, (EIS_VIDEO_FMT_ATTR_S*)pComponentConfigStructure); } break; case COMP_IndexVendorEisDataProcAttr: { eError = DoSetEisChnDataProcOpr(hComponent, (EIS_DATA_PROC_ATTR_S*)pComponentConfigStructure); } break; case COMP_IndexVendorEisGyroAttr: { eError = DoSetEisChnGyroOpr(hComponent, (EIS_GYRO_DATA_ATTR_S*)pComponentConfigStructure); } break; case COMP_IndexVendorEisKmatAttr: { eError = DoSetEisChnKmatOpr(hComponent, (EIS_KMAT_S*)pComponentConfigStructure); } break; case COMP_IndexVendorMPPChannelInfo: { eError = DoVideoEisMPPChannelInfoOpr(hComponent, (MPP_CHN_S *)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; case COMP_IndexVendorEisEnable: { eError = DoVideoEisChnEnableOpr(hComponent, (int*)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; case COMP_IndexVendorEisReleaseData: { eError = DoVideoEisReleaseData(hComponent, (EIS_PARAMS_S *)pComponentConfigStructure); } break; case COMP_IndexVendorEisStoreFrame: { eError = DoVideoEisStoreFrameOpr(hComponent, (const char*)pComponentConfigStructure); } break; case COMP_IndexVendorEisFreq: { eError = DoVideoEisFreqOpr(hComponent, (int*)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; case COMP_IndexParamPortDefinition: { eError = DoVideoEisPortDefinitionOpr(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; case COMP_IndexParamCompBufferSupplier: { eError = DoVideoEisCompBufferSupplierOpr(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure, EIS_CHN_CONF_SET); } break; default: { aloge("Unknown EIS configuration index[0x%x]", nIndex); eError = ERR_EIS_NOT_SUPPORT; } break; } return eError; } ERRORTYPE VideoEISComponentTunnelRequest(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN unsigned int nPort, PARAM_IN COMP_HANDLETYPE hTunneledComp, PARAM_IN unsigned int nTunneledPort, PARAM_INOUT COMP_TUNNELSETUPTYPE *pTunnelSetup) { ERRORTYPE eError = SUCCESS; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); COMP_PARAM_PORTDEFINITIONTYPE *pPortDef; COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo; COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier; int i; /* You can bind input ports and output ports, *but better not do this in Executing state */ if (pVideoEISData->state == COMP_StateExecuting) { alogw("Be careful! tunnel request may be some danger in StateExecuting"); } else if (pVideoEISData->state != COMP_StateIdle) { aloge("Fatal error! tunnel request can't be in state[0x%x]",pVideoEISData->state); eError = ERR_EIS_INCORRECT_STATE_OPERATION; goto EBind; } for (i = 0; i < EIS_CHN_MAX_PORTS; ++i) { if (pVideoEISData->sPortDef[i].nPortIndex == nPort) { pPortDef = &pVideoEISData->sPortDef[i]; break; } } if (i == EIS_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_EIS_INVALID_PARA; goto EBind; } for (i = 0; i < EIS_CHN_MAX_PORTS; ++i) { if (pVideoEISData->sPortTunnelInfo[i].nPortIndex == nPort) { pPortTunnelInfo = &pVideoEISData->sPortTunnelInfo[i]; break; } } if (i == EIS_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_EIS_INVALID_PARA; goto EBind; } for (i = 0; i < EIS_CHN_MAX_PORTS; ++i) { if (pVideoEISData->sPortBufSupplier[i].nPortIndex == nPort) { pPortBufSupplier = &pVideoEISData->sPortBufSupplier[i]; break; } } if (i == EIS_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_EIS_INVALID_PARA; goto EBind; } pPortTunnelInfo->nPortIndex = nPort; pPortTunnelInfo->hTunnel = hTunneledComp; pPortTunnelInfo->nTunnelPortIndex = nTunneledPort; pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON; /* When all the parameters is zero, we unbind it, it is a engage */ if(NULL == hTunneledComp && 0 == nTunneledPort && NULL == pTunnelSetup) { alogd("Receive a cancel setup tunnel request on port[%d]", nPort); pPortTunnelInfo->hTunnel = NULL; if(pPortDef->eDir == COMP_DirOutput) pVideoEISData->bOutputPortTunnelFlag = FALSE; else if (pPortDef->eDir == COMP_DirInput) pVideoEISData->bInputPortTunnelFlag = FALSE; eError = SUCCESS; goto EBind; } if(pPortDef->eDir == COMP_DirOutput) { if (pVideoEISData->bOutputPortTunnelFlag) { aloge("EIS component[%d] output port has already binded, why bind again?!", pVideoEISData->mMppChnInfo.mChnId); eError = ERR_EIS_NOT_PERM; goto EBind; } pTunnelSetup->nTunnelFlags = 0; pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier; pVideoEISData->bOutputPortTunnelFlag = TRUE; } else if (pPortDef->eDir == COMP_DirInput && pVideoEISData->mEISAttr.bSimuOffline){ aloge("EIS component[%d] input port can't be bind in offline simulation mode.", pVideoEISData->mMppChnInfo.mChnId); eError = ERR_EIS_NOT_PERM; goto EBind; } else if (pPortDef->eDir == COMP_DirInput) { if (pVideoEISData->bInputPortTunnelFlag) { aloge("EIS component[%d] input port has already binded, why bind again?!", pVideoEISData->mMppChnInfo.mChnId); eError = ERR_EIS_NOT_PERM; goto EBind; } /* Check the data compatibility between the ports using one or more GetParameter calls. */ /* B checks if its input port is compatible with the output port of component A. */ COMP_PARAM_PORTDEFINITIONTYPE stTunnelPortDef; stTunnelPortDef.nPortIndex = nTunneledPort; COMP_GetConfig(hTunneledComp, COMP_IndexParamPortDefinition, &stTunnelPortDef); if(stTunnelPortDef.eDir != COMP_DirOutput) { aloge("Fatal error! you are binding a input tunnel port[index%d] to an input port[index%d].", nTunneledPort, pPortDef->nPortIndex); eError = ERR_EIS_INVALID_PARA; goto EBind; } #if 0 if (strcmp((const char*)&pPortDef->format, (const char*)&stTunnelPortDef.format)) { aloge("Fatal error! you are binding a output tunnel port[fmt%d] to an input port[fmt%d].", stTunnelPortDef.format, pPortDef->format); eError = ERR_EIS_INVALID_PARA; goto EBind; } #endif /* The component B informs component A about the final result of negotiation. */ if(pTunnelSetup->eSupplier != pPortBufSupplier->eBufferSupplier) { alogw("Low probability! use input portIndex[%d] buffer supplier[%d] as final!", nPort, pPortBufSupplier->eBufferSupplier); pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier; } COMP_PARAM_BUFFERSUPPLIERTYPE oSupplier; oSupplier.nPortIndex = nTunneledPort; COMP_GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier); oSupplier.eBufferSupplier = pTunnelSetup->eSupplier; COMP_SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier); pVideoEISData->bInputPortTunnelFlag = TRUE; } EBind: return eError; } static void DoVideoEisSendBackInputFrame (VIDEOEISDATATYPE *pVideoEisData, VIDEO_FRAME_INFO_S *pFrameInfo) { COMP_BUFFERHEADERTYPE BufferHeader; memset(&BufferHeader, 0, sizeof(COMP_BUFFERHEADERTYPE)); if (FALSE == pVideoEisData->bInputPortTunnelFlag) { BufferHeader.pAppPrivate = pFrameInfo; pVideoEisData->pCallbacks->EmptyBufferDone(pVideoEisData->hSelf, pVideoEisData->pAppData, &BufferHeader); } else { BufferHeader.pOutputPortPrivate = pFrameInfo; MM_COMPONENTTYPE *pTunnelComp = (MM_COMPONENTTYPE *)pVideoEisData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_VIDEO_IN].hTunnel; BufferHeader.nOutputPortIndex = pVideoEisData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_VIDEO_IN].nTunnelPortIndex; COMP_FillThisBuffer(pTunnelComp, &BufferHeader); } alogv("Release input FrameId[%d].", pFrameInfo->mId); } static void DoVideoEisReturnBackAllInputFrames(VIDEOEISDATATYPE *pVideoEisData) { VIDEO_FRAME_INFO_S *pFrameInfo = NULL; VIDEO_FRAME_INFO_S stFrameInfoRet; while (1) { pFrameInfo = VideoBufMgrGetAllValidUsingFrame(pVideoEisData->pInputBufMgr); if (NULL == pFrameInfo) break; stFrameInfoRet = *pFrameInfo; DoVideoEisSendBackInputFrame(pVideoEisData, &stFrameInfoRet); } alogw("Return all input frames done, EIS Chn[%d].", pVideoEisData->mMppChnInfo.mChnId); } ERRORTYPE VideoEISEmptyThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer) { ERRORTYPE eError = SUCCESS; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state != COMP_StateExecuting) { alogw("Send frame when EIS component state[0x%x] isn not executing", pVideoEISData->state); eError = ERR_EIS_NOT_PERM; pthread_mutex_unlock(&pVideoEISData->mStateLock); goto EState; } pthread_mutex_unlock(&pVideoEISData->mStateLock); /* put data ptr to CapMgr_queue for tunnel or user mpi_get\release */ if (pBuffer->nInputPortIndex == pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].nPortIndex) { VIDEO_FRAME_INFO_S *pVInputFrm = NULL; if(pVideoEISData->bInputPortTunnelFlag) pVInputFrm = (VIDEO_FRAME_INFO_S *)pBuffer->pOutputPortPrivate; else pVInputFrm = (VIDEO_FRAME_INFO_S *)pBuffer->pAppPrivate; eError = VideoBufMgrPushFrame(pVideoEISData->pInputBufMgr, pVInputFrm); if (eError != SUCCESS) { aloge("Failed to push this frame, it will be droped\n"); eError = ERR_EIS_BUF_FULL; goto EPushFrm; } alogv("VideoEisEmptyThisBuffer pushFrame process, %p.\r\n", pVInputFrm->VFrame.mpVirAddr[0]); if (pVideoEISData->bWaitingInputFrmFlag) { message_t msg; msg.command = EisComp_InputFrameAvailable; put_message(&pVideoEISData->cmd_queue, &msg); } } else if (pBuffer->nInputPortIndex == pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].nPortIndex) { /* We accept gyro datas and ready to process it. */ EIS_GYRO_PACKET_S *pVInputGyroPkt = NULL; if(pVideoEISData->bInputPortTunnelFlag) pVInputGyroPkt = (EIS_GYRO_PACKET_S *)pBuffer->pOutputPortPrivate; else pVInputGyroPkt = (EIS_GYRO_PACKET_S *)pBuffer->pAppPrivate; if (ring_buffer_full(pVideoEISData->GryoRingBufHd)) { EIS_GYRO_PACKET_S stGyroPktOut; aloge("Gyro ring buffer is full, drop the oldest gyro data."); ring_buffer_out(pVideoEISData->GryoRingBufHd, &stGyroPktOut, pBuffer->nFilledLen); } ring_buffer_in(pVideoEISData->GryoRingBufHd, pVInputGyroPkt, pBuffer->nFilledLen); } else { aloge("fatal error! inputPortIndex[%d] match nothing!", pBuffer->nOutputPortIndex); } EPushFrm: EState: return eError; } ERRORTYPE VideoEISFillThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer) { VIDEOEISDATATYPE *pVideoEISData; ERRORTYPE eError = SUCCESS; int ret; pVideoEISData = (VIDEOEISDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo = &pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_VIDEO_IN]; MM_COMPONENTTYPE *pInTunnelComp = (MM_COMPONENTTYPE*)pPortTunnelInfo->hTunnel; /* First of all, this interface can be used only in bind mode. */ if (!pVideoEISData->bOutputPortTunnelFlag) { aloge("You can not invoke this interface in non-tunnel out port mode."); eError = ERR_EIS_NOT_PERM; } if (pBuffer->nOutputPortIndex == pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].nPortIndex && pInTunnelComp) { VIDEO_FRAME_INFO_S *pstFrameInfo = pBuffer->pAppPrivate; VideoFrameListInfo *pVFrmList; bool bFindFlag = 0; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); list_for_each_entry(pVFrmList, &pVideoEISData->mOutUsedList, mList) { if (pVFrmList->mFrame.mId == pstFrameInfo->mId || pVFrmList->mFrame.VFrame.mpVirAddr[0] == pstFrameInfo->VFrame.mpVirAddr[0]) { bFindFlag = 1; break; } } if (bFindFlag) { list_move_tail(&pVFrmList->mList, &pVideoEISData->mOutIdleList); pVideoEISData->iOutFrmIdleCnt++; } else { aloge("No such video frame Id[%d]VirAddr[%p] is using, please check it.", pstFrameInfo->mId, pstFrameInfo->VFrame.mpVirAddr[0]); eError = ERR_EIS_INVALID_PARA; } pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); } else { aloge("Fatal error! outputPortIndex[%d]!=[%d]", pBuffer->nOutputPortIndex, pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].nPortIndex); } return eError; } static void _EisTraverOutputBufPool(VIDEOEISDATATYPE *pVideoEISData) { VideoFrameListInfo* EisOutFrmTmp = NULL; VideoFrameListInfo* EisOutFrmCur = NULL; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); if (!list_empty(&pVideoEISData->mOutUsedList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutUsedList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); } } EisOutFrmCur = NULL; } if (!list_empty(&pVideoEISData->mOutValidList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutValidList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); } } EisOutFrmCur = NULL; } if (!list_empty(&pVideoEISData->mOutIdleList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutIdleList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); } } EisOutFrmCur = NULL; } pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); } ERRORTYPE _EisCreateOutputBufPool(VIDEOEISDATATYPE *pVideoEISData) { int i = 0; int iPoolBufNum = pVideoEISData->mEISAttr.iOutputBufBum; VideoFrameListInfo* EisOutFrm; ERRORTYPE eError = SUCCESS; pthread_mutex_init(&pVideoEISData->mOutFrmListLock, NULL); INIT_LIST_HEAD(&pVideoEISData->mOutIdleList); INIT_LIST_HEAD(&pVideoEISData->mOutValidList); INIT_LIST_HEAD(&pVideoEISData->mOutUsedList); for (i = 0; i < iPoolBufNum; i++) { /* alloc size for output buffers */ EisOutFrm = malloc(sizeof(VideoFrameListInfo)); if (NULL == EisOutFrm) continue; EisOutFrm->mFrame.VFrame.mpVirAddr[0] = ion_allocMem( pVideoEISData->mEISAttr.iVideoOutWidth*pVideoEISData->mEISAttr.iVideoOutHeight); EisOutFrm->mFrame.VFrame.mpVirAddr[1] = ion_allocMem( pVideoEISData->mEISAttr.iVideoOutWidth*pVideoEISData->mEISAttr.iVideoOutHeight/2); EisOutFrm->mFrame.VFrame.mPhyAddr[0] = ion_getMemPhyAddr(EisOutFrm->mFrame.VFrame.mpVirAddr[0]); EisOutFrm->mFrame.VFrame.mPhyAddr[1] = ion_getMemPhyAddr(EisOutFrm->mFrame.VFrame.mpVirAddr[1]); EisOutFrm->mFrame.VFrame.mWidth = pVideoEISData->mEISAttr.iVideoOutWidth; EisOutFrm->mFrame.VFrame.mHeight = pVideoEISData->mEISAttr.iVideoOutHeight; EisOutFrm->mFrame.VFrame.mOffsetTop = 0; EisOutFrm->mFrame.VFrame.mOffsetLeft = 0; EisOutFrm->mFrame.VFrame.mOffsetRight = pVideoEISData->mEISAttr.iVideoOutWidth; EisOutFrm->mFrame.VFrame.mOffsetBottom = pVideoEISData->mEISAttr.iVideoOutHeight; EisOutFrm->mFrame.VFrame.mField = VIDEO_FIELD_FRAME; EisOutFrm->mFrame.VFrame.mVideoFormat = VIDEO_FORMAT_LINEAR; EisOutFrm->mFrame.VFrame.mCompressMode = COMPRESS_MODE_NONE; EisOutFrm->mFrame.VFrame.mStride[0] = 0; EisOutFrm->mFrame.VFrame.mStride[1] = 0; EisOutFrm->mFrame.VFrame.mStride[2] = 0; EisOutFrm->mFrame.VFrame.mPixelFormat = pVideoEISData->mEISAttr.eVideoFmt; EisOutFrm->mFrame.mId = pVideoEISData->iOutFrmCnt; list_add_tail(&EisOutFrm->mList, &pVideoEISData->mOutIdleList); pVideoEISData->iOutFrmCnt++; } pVideoEISData->iOutFrmIdleCnt = pVideoEISData->iOutFrmCnt; // _EisTraverOutputBufPool(pVideoEISData); return eError; } void _EisDestroyOutputBufPool(VIDEOEISDATATYPE *pVideoEISData) { VideoFrameListInfo* EisOutFrmTmp = NULL; VideoFrameListInfo* EisOutFrmCur = NULL; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); if (!list_empty(&pVideoEISData->mOutUsedList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutUsedList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[0]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); free(EisOutFrmCur); } } EisOutFrmCur = NULL; } if (!list_empty(&pVideoEISData->mOutValidList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutValidList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[0]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); free(EisOutFrmCur); } } EisOutFrmCur = NULL; } if (!list_empty(&pVideoEISData->mOutIdleList)) { list_for_each_entry_safe(EisOutFrmCur, EisOutFrmTmp, &pVideoEISData->mOutIdleList, mList) { if (EisOutFrmCur) { aloge("Release video input frame[%d], vir addr[%p][%p].", EisOutFrmCur->mFrame.mId, EisOutFrmCur->mFrame.VFrame.mpVirAddr[0], EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[0]); ion_freeMem(EisOutFrmCur->mFrame.VFrame.mpVirAddr[1]); free(EisOutFrmCur); } } EisOutFrmCur = NULL; } pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); pthread_mutex_destroy(&pVideoEISData->mOutFrmListLock); } static void _EisDumpHardwareLibConfigs(EISE_CFG_PARA *pEisCfg) { printf("Dump EIS hardware driver config:\r\n"); printf("\t in_w:\t%d\r\n", pEisCfg->in_w); printf("\t in_h:\t%d\r\n", pEisCfg->in_h); printf("\t out_h:\t%d\r\n", pEisCfg->out_h); printf("\t out_w:\t%d\r\n", pEisCfg->out_w); printf("\t hor_off:\t%d\r\n", pEisCfg->hor_off); printf("\t vor_off:\t%d\r\n", pEisCfg->ver_off); if (pEisCfg->in_yuv_type == PLANE_YUV420) { printf("\t in_yuv_type:\tYUV420\r\n"); } else if (pEisCfg->in_yuv_type == PLANE_YVU420) { printf("\t in_yuv_type:\tYVU420\r\n"); } if (pEisCfg->out_yuv_type == PLANE_YUV420) printf("\t out_yuv_type:\tYUV420\r\n"); else if (pEisCfg->out_yuv_type == PLANE_YVU420) printf("\t out_yuv_type:\tYVU420\r\n"); printf("\t in_luma_pitch:\t%d\r\n", pEisCfg->in_luma_pitch); printf("\t in_chroma_pitch:\t%d\r\n", pEisCfg->in_chroma_pitch); printf("\t out_luma_pitch:\t%d\r\n", pEisCfg->out_luma_pitch); printf("\t out_chroma_pitch:\t%d\r\n", pEisCfg->out_chroma_pitch); printf("\t src_width:\t%d\r\n", pEisCfg->src_width); printf("\t src_height:\t%d\r\n", pEisCfg->src_height); printf("\t cut_height:\t%d\r\n", pEisCfg->cut_height); printf("\t rt:\t%f\r\n", pEisCfg->rt); printf("\t k_matrix[0]:\t%f\r\n", pEisCfg->k_matrix[0]); printf("\t k_matrix[1]:\t%f\r\n", pEisCfg->k_matrix[2]); printf("\t k_matrix[2]:\t%f\r\n", pEisCfg->k_matrix[4]); printf("\t k_matrix[3]:\t%f\r\n", pEisCfg->k_matrix[5]); printf("\t k_matrix[8]:\t%f\r\n", pEisCfg->k_matrix[8]); printf("\t ts:\t%f\r\n", pEisCfg->ts); printf("\t td:\t%f\r\n", pEisCfg->td); printf("\t stable_anglev[0]:\t%f\r\n", pEisCfg->stable_anglev[0]); printf("\t stable_anglev[1]:\t%f\r\n", pEisCfg->stable_anglev[1]); printf("\t stable_anglev[2]:\t%f\r\n", pEisCfg->stable_anglev[2]); printf("\t angle_th[0]:\t%f\r\n", pEisCfg->angle_th[0]); printf("\t angle_th[1]:\t%f\r\n", pEisCfg->angle_th[1]); printf("\t angle_th[2]:\t%f\r\n", pEisCfg->angle_th[2]); printf("\t radius[0]:\t%d\r\n", pEisCfg->radius[0]); printf("\t radius[1]:\t%d\r\n", pEisCfg->radius[1]); printf("\t radius[2]:\t%d\r\n", pEisCfg->radius[2]); printf("\t video fps:\t%d\r\n", pEisCfg->fps); printf("\t filter_type:\t%d\r\n", pEisCfg->filter_type); printf("\t xy_exchange_en:\t%d\r\n", pEisCfg->xy_exchange_en); printf("\t rolling_shutter:\t%d\r\n", pEisCfg->rolling_shutter); printf("\t rs_correction_en:\t%d\r\n", pEisCfg->rs_correction_en); printf("\t frame_rotation_en:\t%d\r\n", pEisCfg->frame_rotation_en); printf("\t fast_mode:\t%d\r\n", pEisCfg->fast_mode); printf("\t g_en_angle_filter:\t%d\r\n", pEisCfg->g_en_angle_filter); printf("\t g_interlace:\t%d\r\n", pEisCfg->g_interlace); printf("\t max_frm_buf:\t%d\r\n", pEisCfg->max_frm_buf); printf("\t max_next_frm:\t%d\r\n", pEisCfg->max_next_frm); } static void VideoEisSetHwCfgs(VIDEOEISDATATYPE *pVideoEISData) { pVideoEISData->mEisCfg.in_w = pVideoEISData->mEISAttr.iVideoInWidth; pVideoEISData->mEisCfg.in_h = pVideoEISData->mEISAttr.iVideoInHeight; // 1080p@30fps pVideoEISData->mEisCfg.out_h = pVideoEISData->mEISAttr.iVideoOutHeight; pVideoEISData->mEisCfg.out_w = pVideoEISData->mEISAttr.iVideoOutWidth; pVideoEISData->mEisCfg.hor_off = (int)((float)(pVideoEISData->mEISAttr.iVideoInWidth-pVideoEISData->mEISAttr.iVideoOutWidth)/64+0.5)*32; pVideoEISData->mEisCfg.ver_off = (int)((float)(pVideoEISData->mEISAttr.iVideoInHeight-pVideoEISData->mEISAttr.iVideoOutHeight)/64+0.5)*32; pVideoEISData->mEisCfg.in_yuv_type = (pVideoEISData->mEISAttr.eVideoFmt == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420) ? PLANE_YUV420 : PLANE_YVU420; pVideoEISData->mEisCfg.out_yuv_type = (pVideoEISData->mEISAttr.eVideoFmt == MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420) ? PLANE_YUV420 : PLANE_YVU420; pVideoEISData->mEisCfg.in_luma_pitch = pVideoEISData->mEISAttr.iVideoInWidth; pVideoEISData->mEisCfg.in_chroma_pitch = pVideoEISData->mEISAttr.iVideoInWidth; pVideoEISData->mEisCfg.out_luma_pitch = pVideoEISData->mEISAttr.iVideoOutWidth; pVideoEISData->mEisCfg.out_chroma_pitch = pVideoEISData->mEISAttr.iVideoOutWidth; switch (pVideoEISData->mEISAttr.eOperationMode) { /* Just all use EIS_OPR_1080P30 configuration until now. */ case EIS_OPR_4K30: { pVideoEISData->mEisCfg.src_width = 4032; pVideoEISData->mEisCfg.src_height = 2256; pVideoEISData->mEisCfg.cut_height = 2256; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 2478.96f; pVideoEISData->mEisCfg.k_matrix[2] = 1983.4f; pVideoEISData->mEisCfg.k_matrix[4] = 2486.28f; pVideoEISData->mEisCfg.k_matrix[5] = 1165.32f; pVideoEISData->iVideoLineTime = 30; pVideoEISData->mEisCfg.g_interlace = 1; } break; case EIS_OPR_2P7K30: { pVideoEISData->mEisCfg.src_width = 3840; pVideoEISData->mEisCfg.src_height = 2160; pVideoEISData->mEisCfg.cut_height = 2160; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 1960.0f; pVideoEISData->mEisCfg.k_matrix[2] = 1680.0f; pVideoEISData->mEisCfg.k_matrix[4] = 1960.0f; pVideoEISData->mEisCfg.k_matrix[5] = 944.0f; pVideoEISData->iVideoLineTime = 30; pVideoEISData->mEisCfg.g_interlace = 1; } break; case EIS_OPR_VGA30: { pVideoEISData->mEisCfg.src_width = 3840; pVideoEISData->mEisCfg.src_height = 2160; pVideoEISData->mEisCfg.cut_height = 2160; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 466.67f; pVideoEISData->mEisCfg.k_matrix[2] = 400.0f; pVideoEISData->mEisCfg.k_matrix[4] = 466.67f; pVideoEISData->mEisCfg.k_matrix[5] = 224.0f; pVideoEISData->iVideoLineTime = 30; pVideoEISData->mEisCfg.g_interlace = 1; } break; case EIS_OPR_1080P30: { pVideoEISData->mEisCfg.src_width = 3840; pVideoEISData->mEisCfg.src_height = 2160; pVideoEISData->mEisCfg.cut_height = 2160; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 1400.0f; pVideoEISData->mEisCfg.k_matrix[2] = 1200.0f; pVideoEISData->mEisCfg.k_matrix[4] = 1400.0f; pVideoEISData->mEisCfg.k_matrix[5] = 672.0f; pVideoEISData->iVideoLineTime = 30; pVideoEISData->mEisCfg.g_interlace = 1; } break; /* keep default settings */ case EIS_OPR_VGA60: { pVideoEISData->mEisCfg.src_width = 2016; pVideoEISData->mEisCfg.src_height = 1128; pVideoEISData->mEisCfg.cut_height = 1128; pVideoEISData->mEisCfg.rt = (float)2256 / (294*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 467.82f; pVideoEISData->mEisCfg.k_matrix[2] = 400.0f; pVideoEISData->mEisCfg.k_matrix[4] = 467.82f; pVideoEISData->mEisCfg.k_matrix[5] = 224.0f; pVideoEISData->iVideoLineTime = 9; pVideoEISData->mEisCfg.g_interlace = 2; } break; case EIS_OPR_1080P60: { pVideoEISData->mEisCfg.src_width = 2016; pVideoEISData->mEisCfg.src_height = 1128; pVideoEISData->mEisCfg.cut_height = 1128; pVideoEISData->mEisCfg.rt = (float)2256 / (294*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 1400.0f; pVideoEISData->mEisCfg.k_matrix[2] = 1008.0f; pVideoEISData->mEisCfg.k_matrix[4] = 1400.0f; pVideoEISData->mEisCfg.k_matrix[5] = 564.0f; pVideoEISData->iVideoLineTime = 9; pVideoEISData->mEisCfg.g_interlace = 2; } break; case EIS_OPR_DEBUG_RES: { pVideoEISData->mEisCfg.src_width = 3840; pVideoEISData->mEisCfg.src_height = 2160; pVideoEISData->mEisCfg.cut_height = 2160; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 1680.0f; pVideoEISData->mEisCfg.k_matrix[2] = 1440.0f; pVideoEISData->mEisCfg.k_matrix[4] = 1680.0f; pVideoEISData->mEisCfg.k_matrix[5] = 816.0f; pVideoEISData->iVideoLineTime = 30; } break; default: { pVideoEISData->mEisCfg.src_width = 3840; pVideoEISData->mEisCfg.src_height = 2160; pVideoEISData->mEisCfg.cut_height = 2160; pVideoEISData->mEisCfg.rt = (float)4296 / (300*1000*1000); pVideoEISData->mEisCfg.k_matrix[0] = 3735.99; pVideoEISData->mEisCfg.k_matrix[2] = 1188.06; pVideoEISData->mEisCfg.k_matrix[4] = 3665.66; pVideoEISData->mEisCfg.k_matrix[5] = 680.34; pVideoEISData->iVideoLineTime = 30; pVideoEISData->mEisCfg.g_interlace = 1; aloge("You set a wrong operation mode[%d], use EIS_OPR_1080P30 by default.", pVideoEISData->mEISAttr.eOperationMode); } break; } if (pVideoEISData->mEISAttr.bUseKmat) { pVideoEISData->mEisCfg.k_matrix[0] = pVideoEISData->mEISAttr.stEisKmat.KmatK1; pVideoEISData->mEisCfg.k_matrix[2] = pVideoEISData->mEISAttr.stEisKmat.KmatK2; pVideoEISData->mEisCfg.k_matrix[4] = pVideoEISData->mEISAttr.stEisKmat.KmatKx; pVideoEISData->mEisCfg.k_matrix[5] = pVideoEISData->mEISAttr.stEisKmat.KmatKy; } pVideoEISData->mEisCfg.k_matrix[8] = 1; pVideoEISData->mEisCfg.ts = (float)pVideoEISData->mEisCfg.cut_height * pVideoEISData->mEisCfg.rt; pVideoEISData->mEisCfg.td = 0; // (float)(pVideoEISData->mEisCfg.src_height - pVideoEISData->mEisCfg.cut_height)/2*pVideoEISData->mEisCfg.rt; #if 1 pVideoEISData->mEisCfg.stable_anglev[0] = 0.06155; pVideoEISData->mEisCfg.stable_anglev[1] = 0.015; pVideoEISData->mEisCfg.stable_anglev[2] = -0.0173; #else pVideoEISData->mEisCfg.stable_anglev[0] = 0.0082; pVideoEISData->mEisCfg.stable_anglev[1] = -0.0052; pVideoEISData->mEisCfg.stable_anglev[2] = -0.0155; #endif #ifndef PI #define PI 3.141592653589793 #endif pVideoEISData->mEisCfg.angle_th[0] = 0; pVideoEISData->mEisCfg.angle_th[1] = 0; pVideoEISData->mEisCfg.angle_th[2] = 2*PI/180; switch(pVideoEISData->mEisCfg.out_w) { case 2688: case 2304: pVideoEISData->mEisCfg.radius[0] = 17; pVideoEISData->mEisCfg.radius[1] = 2; pVideoEISData->mEisCfg.radius[2] = 1; pVideoEISData->mEisCfg.max_frm_buf = pVideoEISData->mEISAttr.iEisFilterWidth; pVideoEISData->mEisCfg.filter_type = 0; // 0:EIS_LOWPASS; 1:EIS_AVERAGE 2:EIS_POLYFIT1 pVideoEISData->mEisCfg.g_en_angle_filter = 0; break; case 1600: case 1920: //pVideoEISData->mEisCfg.radius[0] = 17; //pVideoEISData->mEisCfg.radius[1] = 2; //pVideoEISData->mEisCfg.radius[2] = 1; //pVideoEISData->mEisCfg.max_frm_buf = pVideoEISData->mEISAttr.iEisFilterWidth; //pVideoEISData->mEisCfg.filter_type = 0; // 0:EIS_LOWPASS; 1:EIS_AVERAGE 2:EIS_POLYFIT1 //pVideoEISData->mEisCfg.g_en_angle_filter = 0; pVideoEISData->mEisCfg.radius[1] = 2; pVideoEISData->mEisCfg.radius[2] = 1; pVideoEISData->mEisCfg.radius[0] = pVideoEISData->mEISAttr.iEisFilterWidth -pVideoEISData->mEisCfg.radius[1]-pVideoEISData->mEisCfg.radius[2]; if (pVideoEISData->mEisCfg.radius[0] < pVideoEISData->mEisCfg.radius[1]) { aloge("You set a wrong input buffer[%d], use [%d] by default.", pVideoEISData->mEisCfg.radius[1]); pVideoEISData->mEisCfg.radius[0] = pVideoEISData->mEisCfg.radius[1]; } break; case 640: default: pVideoEISData->mEisCfg.radius[0] = 17; pVideoEISData->mEisCfg.radius[1] = 1; pVideoEISData->mEisCfg.radius[2] = 0; pVideoEISData->mEisCfg.max_frm_buf = pVideoEISData->mEISAttr.iEisFilterWidth > 4 ? 4 : pVideoEISData->mEISAttr.iEisFilterWidth; pVideoEISData->mEisCfg.filter_type = 0; // 0:EIS_LOWPASS; 1:EIS_AVERAGE 2:EIS_POLYFIT1 pVideoEISData->mEisCfg.g_en_angle_filter = 0; break; } if (pVideoEISData->mEISAttr.iInputBufNum < pVideoEISData->mEISAttr.iEisFilterWidth) pVideoEISData->mEISAttr.bRetInFrmFast = 1; if (pVideoEISData->mEISAttr.bVerticalFlip && pVideoEISData->mEISAttr.bHorizFlip) { pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor = 1; } else if (!pVideoEISData->mEISAttr.bVerticalFlip && pVideoEISData->mEISAttr.bHorizFlip) { pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor = -1; } else if (pVideoEISData->mEISAttr.bVerticalFlip && !pVideoEISData->mEISAttr.bHorizFlip) { pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor = -1; pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor = -1; } else if (!pVideoEISData->mEISAttr.bVerticalFlip && !pVideoEISData->mEISAttr.bHorizFlip) { pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor = 1; pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor = 1; } pVideoEISData->mEisCfg.fps = pVideoEISData->mEISAttr.iVideoFps; pVideoEISData->mEisCfg.xy_exchange_en = 1; pVideoEISData->mEisCfg.rolling_shutter = 0; pVideoEISData->mEisCfg.fast_mode = 0; if (pVideoEISData->mEISAttr.eOperationMode == EIS_OPR_VGA30 || pVideoEISData->mEISAttr.eOperationMode == EIS_OPR_VGA60) { pVideoEISData->mEisCfg.filter_type = 0; pVideoEISData->mEisCfg.g_en_angle_filter = 0; pVideoEISData->mEisCfg.max_frm_buf = 1 + pVideoEISData->mEisCfg.radius[1] + pVideoEISData->mEisCfg.radius[2]; pVideoEISData->mEisCfg.max_next_frm = pVideoEISData->mEisCfg.max_frm_buf - pVideoEISData->mEisCfg.radius[1] - pVideoEISData->mEisCfg.radius[2]; } else if(pVideoEISData->mEISAttr.eOperationMode == EIS_OPR_1080P30 || pVideoEISData->mEISAttr.eOperationMode == EIS_OPR_1080P60){ pVideoEISData->mEisCfg.filter_type = 0; pVideoEISData->mEisCfg.g_en_angle_filter = 0; pVideoEISData->mEisCfg.max_frm_buf = pVideoEISData->mEisCfg.radius[0] + pVideoEISData->mEisCfg.radius[1] + pVideoEISData->mEisCfg.radius[2]; pVideoEISData->mEisCfg.max_next_frm = pVideoEISData->mEisCfg.max_frm_buf - pVideoEISData->mEisCfg.radius[1] - pVideoEISData->mEisCfg.radius[2]; }else { pVideoEISData->mEisCfg.max_next_frm = pVideoEISData->mEisCfg.max_frm_buf - pVideoEISData->mEisCfg.radius[1] - pVideoEISData->mEisCfg.radius[2]; } pVideoEISData->mEisCfg.rs_correction_en = 1; /* Only when frame_rotation_en == 1, it make sense. */ pVideoEISData->mEisCfg.frame_rotation_en = 1; pVideoEISData->mEisCfg.old_radius_th0 = 3; pVideoEISData->mEisCfg.old_radius_th1 = 5; _EisDumpHardwareLibConfigs(&pVideoEISData->mEisCfg); } #if 0 static void _EisDumpSoftwareLibConfigs(EISE_CFG_PARA *pEisCfg) { printf("Dump EIS hardware driver config:\r\n"); printf("\t in_w:\t%d\r\n", pEisCfg->in_w); printf("\t in_h:\t%d\r\n", pEisCfg->in_h); printf("\t out_h:\t%d\r\n", pEisCfg->out_h[0]); printf("\t out_w:\t%d\r\n", pEisCfg->out_w[0]); if (pEisCfg->in_yuv_type == YUV420) { printf("\t in_yuv_type:\tYUV420\r\n"); } else if (pEisCfg->in_yuv_type == YVU420) { printf("\t in_yuv_type:\tYVU420\r\n"); } if (pEisCfg->out_yuv_type == YUV420) { printf("\t out_yuv_type:\tYUV420\r\n"); } else if (pEisCfg->out_yuv_type == YVU420) { printf("\t out_yuv_type:\tYVU420\r\n"); } printf("\t in_luma_pitch:\t%d\r\n", pEisCfg->in_luma_pitch); printf("\t in_chroma_pitch:\t%d\r\n", pEisCfg->in_chroma_pitch); printf("\t out_luma_pitch:\t%d\r\n", pEisCfg->out_luma_pitch[0]); printf("\t out_chroma_pitch:\t%d\r\n", pEisCfg->out_chroma_pitch[0]); printf("\t input_width:\t%d\r\n", pEisCfg->input_width); printf("\t output_width:\t%d\r\n", pEisCfg->output_width); printf("\t output_height:\t%d\r\n", pEisCfg->output_height); printf("\t src_width:\t%d\r\n", pEisCfg->src_width); printf("\t src_height:\t%d\r\n", pEisCfg->src_height); printf("\t cut_height:\t%d\r\n", pEisCfg->cut_height); printf("\t rt:\t%f\r\n", pEisCfg->rt); printf("\t k_matrix[0]:\t%f\r\n", pEisCfg->k_matrix[0]); printf("\t k_matrix[1]:\t%f\r\n", pEisCfg->k_matrix[1]); printf("\t k_matrix[2]:\t%f\r\n", pEisCfg->k_matrix[2]); printf("\t k_matrix[3]:\t%f\r\n", pEisCfg->k_matrix[3]); printf("\t k_matrix[8]:\t%f\r\n", pEisCfg->k_matrix[8]); printf("\t ts:\t%f\r\n", pEisCfg->ts); printf("\t td:\t%f\r\n", pEisCfg->td); printf("\t stable_anglev[0]:\t%f\r\n", pEisCfg->stable_anglev[0]); printf("\t stable_anglev[1]:\t%f\r\n", pEisCfg->stable_anglev[1]); printf("\t stable_anglev[2]:\t%f\r\n", pEisCfg->stable_anglev[2]); printf("\t angle_th[0]:\t%f\r\n", pEisCfg->angle_th[0]); printf("\t angle_th[1]:\t%f\r\n", pEisCfg->angle_th[1]); printf("\t angle_th[2]:\t%f\r\n", pEisCfg->angle_th[2]); printf("\t radius[0]:\t%d\r\n", pEisCfg->radius[0]); printf("\t radius[1]:\t%d\r\n", pEisCfg->radius[1]); printf("\t radius[2]:\t%d\r\n", pEisCfg->radius[2]); printf("\t filter_type:\t%d\r\n", pEisCfg->filter_type); printf("\t xy_exchange_en:\t%d\r\n", pEisCfg->xy_exchange_en); printf("\t rolling_shutter:\t%d\r\n", pEisCfg->rolling_shutter); } static void VideoEisSetSwCfgs(VIDEOEISDATATYPE *pVideoEISData) { float KmatK1 = 1680.0f; float KmatK2 = 1583.6f; float KmatKx = 1502.2f; float KmatKy = 863.9f; pVideoEISData->mSwEISCfg.frame_width = 2496; pVideoEISData->mSwEISCfg.frame_height = 1408; pVideoEISData->mSwEISCfg.frame_out2_width = 0; pVideoEISData->mSwEISCfg.frame_out2_height = 0; pVideoEISData->mSwEISCfg.frame_width_stride = 2496; pVideoEISData->mSwEISCfg.frame_height_stride = 1408; pVideoEISData->mSwEISCfg.max_yaw_degrees = 8.5f; pVideoEISData->mSwEISCfg.max_pitch_degrees = 4.5f; pVideoEISData->mSwEISCfg.max_roll_degrees = 1.6f; pVideoEISData->mSwEISCfg.output_scale = 1.0; pVideoEISData->mSwEISCfg.gyro_frequency_in_Hz = (float)pVideoEISData->mEISAttr.iGyroFreq; pVideoEISData->mSwEISCfg.target_fps = 30.0f; pVideoEISData->mSwEISCfg.number_of_input_buffers = 5; pVideoEISData->mSwEISCfg.number_of_output_buffers = pVideoEISData->mEISAttr.iOutputBufBum; pVideoEISData->mSwEISCfg.operation_mode = 3; pVideoEISData->mSwEISCfg.style = 0; //0:normal 1:motion-less switch (pVideoEISData->mEISAttr.iOperationMode) { case 3: case 13: { pVideoEISData->mSwEISCfg.frame_width = 2496; pVideoEISData->mSwEISCfg.frame_height = 1408; pVideoEISData->mSwEISCfg.frame_width_stride = 2496; pVideoEISData->mSwEISCfg.frame_height_stride = 1408; pVideoEISData->mSwEISCfg.max_yaw_degrees = 8.5f; pVideoEISData->mSwEISCfg.max_pitch_degrees = 4.5f; pVideoEISData->mSwEISCfg.max_roll_degrees = 1.6f; pVideoEISData->mSwEISCfg.target_fps = 30.0f; pVideoEISData->mSwEISCfg.number_of_input_buffers = (pVideoEISData->mEISAttr.iOperationMode == 3) ? 5 : 27; pVideoEISData->mSwEISCfg.operation_mode = pVideoEISData->mEISAttr.iOperationMode; } break; } pVideoEISData->mSwEISCfg.frame_height _EisDumpSoftwareLibConfigs(&pVideoEISData->mEisCfg); } #endif //#define DEBUG_GYRO_BUFFER #ifdef DEBUG_GYRO_BUFFER FILE *pBufferInfo[2] = {NULL, NULL}; #endif ERRORTYPE _VideoEisCreate(VIDEOEISDATATYPE *pVideoEISData) { ERRORTYPE eError = SUCCESS; int iRet = 0; int i = 0; if (pVideoEISData->mEisHd && (EIS_ALGO_MODE_BP != pVideoEISData->mEISAttr.eEisAlgoMode)) { alogd("You have already create the EIS handle."); return SUCCESS; } #ifdef DEBUG_GYRO_BUFFER /* create one file to store buffer information */ char pBufferTmp[4096]; char *pTmp = &pBufferTmp[0]; iRet = sprintf(pTmp, "/mnt/extsd/gyro_buffer_info_%dx%d.txt", pVideoEISData->mEISAttr.iVideoInWidth, pVideoEISData->mEISAttr.iVideoInHeight); pTmp += iRet; *pTmp++ = '\0'; pBufferInfo[pVideoEISData->mMppChnInfo.mChnId] = fopen(pBufferTmp, "w+"); if (pBufferInfo[pVideoEISData->mMppChnInfo.mChnId] == NULL) { aloge("open file /mnt/extsd/gyro_buffer_info[%d].txt failed!!", pVideoEISData->mMppChnInfo.mChnId); return eError; } #endif pVideoEISData->pInputBufMgr = VideoBufMgrCreate(pVideoEISData->mEISAttr.iInputBufNum, 0); if (NULL == pVideoEISData->pInputBufMgr) { aloge("Create EIS video input buffer manager failed."); goto ECrtInput; } eError = _EisCreateOutputBufPool(pVideoEISData); if (SUCCESS != eError) { aloge("Create EIS video output buffer pool failed."); goto ECrtOutputPool; } switch (pVideoEISData->mEISAttr.eEisAlgoMode) { case EIS_ALGO_MODE_SW: { aloge("You choice the software EIS, but it can't be use now, so use hardware EIS process."); } case EIS_ALGO_MODE_HW: { pVideoEISData->pstEISPkt = malloc(pVideoEISData->mEISAttr.iInputBufNum*sizeof(EISE_FrameData)); if (NULL == pVideoEISData->pstEISPkt) { aloge("Alloc EIS process packet failed, errno %d.", errno); goto EAllocPkts; } memset(pVideoEISData->pstEISPkt, 0, pVideoEISData->mEISAttr.iInputBufNum*sizeof(EISE_FrameData)); /* All packets has not be used */ pVideoEISData->mEisPktMap = 0; pVideoEISData->pLastUsedEISPkt = NULL; for (i = 0; i < pVideoEISData->mEISAttr.iInputBufNum; i++) pVideoEISData->pstEISPkt[i].fid = i; // Not accumulate. VideoEisSetHwCfgs(pVideoEISData); iRet = EIS_Create(&pVideoEISData->mEisCfg, &pVideoEISData->mEisHd); if (iRet < 0) { aloge("Create EIS hardware handle failed. ret %d.", iRet); eError = ERR_EIS_FAILED_NOTENABLE; goto EEisCrt; } /* If there has no gyro hardware device, then only use unit matrix. */ if (!pVideoEISData->bHasGyroDev && !pVideoEISData->mEISAttr.bSimuOffline) EIS_Set_UnitMatrix_Flag(&pVideoEISData->mEisHd, 0); // EIS_SetFrq(pVideoEISData->iEisHwFreq, &pVideoEISData->mEisHd); } break; case EIS_ALGO_MODE_BP: { char pBufferTmp[4096]; char *pTmp = &pBufferTmp[0]; static int iBPTestCnt = 0; alogw("You choice the by pass EIS mode, I will output the origin gyro and video buffer with no process."); pVideoEISData->bByPassMode = 1; pVideoEISData->pBPDataSavePath = pVideoEISData->mEISAttr.pBPDataSavePath; iRet = sprintf(pTmp, "%s/EISGyroDataCache%dx%dCnt%d.txt", pVideoEISData->pBPDataSavePath, pVideoEISData->mEISAttr.iVideoOutWidth, pVideoEISData->mEISAttr.iVideoOutHeight, iBPTestCnt); pTmp += iRet; *pTmp++ = '\0'; pVideoEISData->pGyroPtsDataFd = fopen(pBufferTmp, "w+"); pTmp = &pBufferTmp[0]; iRet = sprintf(pTmp, "%s/EISVideoPtsCache%dx%dCnt%d.txt", pVideoEISData->pBPDataSavePath, pVideoEISData->mEISAttr.iVideoOutWidth, pVideoEISData->mEISAttr.iVideoOutHeight, iBPTestCnt); pTmp += iRet; *pTmp++ = '\0'; pVideoEISData->pVideoPtsFd = fopen(pBufferTmp, "w+"); if (pVideoEISData->mEISAttr.bSaveYUV) { pTmp = &pBufferTmp[0]; iRet = sprintf(pTmp, "%s/EISpVideoDataCache%dx%dCnt%d.nv12", pVideoEISData->pBPDataSavePath, pVideoEISData->mEISAttr.iVideoOutWidth, pVideoEISData->mEISAttr.iVideoOutHeight, iBPTestCnt); pTmp += iRet; *pTmp++ = '\0'; pVideoEISData->pVideoDataFd = fopen(pBufferTmp, "w+"); } if (!pVideoEISData->pGyroPtsDataFd || !pVideoEISData->pVideoPtsFd || (!pVideoEISData->pVideoDataFd && pVideoEISData->mEISAttr.bSaveYUV)) { aloge("Open %s/xxx cache files failed, check if you have enough space or this path.\r\n", pVideoEISData->pBPDataSavePath); eError = ERR_EIS_FAILED_NOTENABLE; goto EOSaveFd; } if (pVideoEISData->mEISAttr.iVideoOutWidth == 800 && pVideoEISData->mEISAttr.iVideoOutHeight == 448) iBPTestCnt++; } break; default: { aloge("Wrong EIS algoram mode[%d], return.", pVideoEISData->mEISAttr.eEisAlgoMode); eError = ERR_EIS_INVALID_PARA; } break; } return eError; EOSaveFd: if (pVideoEISData->pGyroPtsDataFd) fclose(pVideoEISData->pGyroPtsDataFd); if (pVideoEISData->pVideoPtsFd) fclose(pVideoEISData->pVideoPtsFd); if (pVideoEISData->pVideoDataFd) fclose(pVideoEISData->pVideoDataFd); EEisCrt: _EisDestroyOutputBufPool(pVideoEISData); ECrtOutputPool: free(pVideoEISData->pstEISPkt); EAllocPkts: VideoBufMgrDestroy(pVideoEISData->pInputBufMgr); ECrtInput: return eError; } ERRORTYPE _VideoEisDestroy(VIDEOEISDATATYPE *pVideoEISData) { ERRORTYPE eError = SUCCESS; int iRet = 0; if (!pVideoEISData->mEisHd && (EIS_ALGO_MODE_BP != pVideoEISData->mEISAttr.eEisAlgoMode)) { alogd("You have already destroy the EIS handle."); return SUCCESS; } VideoBufMgrWaitUsingEmpty(pVideoEISData->pInputBufMgr); _EisDestroyOutputBufPool(pVideoEISData); switch (pVideoEISData->mEISAttr.eEisAlgoMode) { case EIS_ALGO_MODE_SW: // Until now, there has no real software EIS process mode. case EIS_ALGO_MODE_HW: { free(pVideoEISData->pstEISPkt); VideoBufMgrDestroy(pVideoEISData->pInputBufMgr); iRet = EIS_Destroy(&pVideoEISData->mEisHd); if (iRet < 0) { aloge("Destroy EIS hardware handle failed. ret %d.", iRet); eError = ERR_EIS_FAILED_NOTDISABLE; } pVideoEISData->mEisHd = NULL; } break; case EIS_ALGO_MODE_BP: { alogw("You choice the bypass EIS mode, and I save all useful datas."); pVideoEISData->bByPassMode = 0; pVideoEISData->pBPDataSavePath = NULL; if (pVideoEISData->pGyroPtsDataFd) fclose(pVideoEISData->pGyroPtsDataFd); if (pVideoEISData->pVideoPtsFd) fclose(pVideoEISData->pVideoPtsFd); if (pVideoEISData->pVideoDataFd) fclose(pVideoEISData->pVideoDataFd); } break; default: { aloge("Wrong EIS algoram mode[%d], return.", pVideoEISData->mEISAttr.eEisAlgoMode); eError = ERR_EIS_INVALID_PARA; } break; } #ifdef DEBUG_GYRO_BUFFER fclose(pBufferInfo[pVideoEISData->mMppChnInfo.mChnId]); #endif return eError; } static void _EisInitAttrs(VIDEOEISDATATYPE* pVideoEISData) { pVideoEISData->iEisHwFreq = 696; pVideoEISData->mEISAttr.iGyroFreq = 1000; pVideoEISData->mEISAttr.iGyroPoolSize = 1000 / pVideoEISData->mEISAttr.iGyroFreq * 1000; pVideoEISData->mEISAttr.iGyroAxiNum = 3; pVideoEISData->mEISAttr.iVideoInWidth = 1920; pVideoEISData->mEISAttr.iVideoOutHeight = 1080; pVideoEISData->mEISAttr.iVideoInWidthStride = 1920; pVideoEISData->mEISAttr.iVideoInHeightStride = 1080; pVideoEISData->mEISAttr.iVideoOutWidth = 1920; pVideoEISData->mEISAttr.iVideoOutHeight = 1080; pVideoEISData->mEISAttr.iVideoFps = 30; pVideoEISData->mEISAttr.eVideoFmt = MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420; pVideoEISData->mEISAttr.iInputBufNum = 11; pVideoEISData->mEISAttr.iOutputBufBum = 10; pVideoEISData->mEISAttr.iEisFilterWidth = 8; pVideoEISData->mEISAttr.bRetInFrmFast = 0; pVideoEISData->mEISAttr.iDelayTimeMs = 1000/pVideoEISData->mEISAttr.iVideoFps; pVideoEISData->mEISAttr.iSyncErrTolerance = 5; /* ms */ pVideoEISData->mEISAttr.bUseKmat = 0; pVideoEISData->mEISAttr.stEisKmat.KmatK1 = 1283.8f; pVideoEISData->mEISAttr.stEisKmat.KmatK2 = 1208.2f; pVideoEISData->mEISAttr.stEisKmat.KmatKx = 1266.9f; pVideoEISData->mEISAttr.stEisKmat.KmatKy = 754.5f; pVideoEISData->mGyroAttr.dev_name = GYRO_DEV_NAME; pVideoEISData->mGyroAttr.dev_dir_path = GYRO_DEV_DIR_PATH; pVideoEISData->mGyroAttr.kfifo_len = 200; pVideoEISData->mGyroAttr.sample_freq = pVideoEISData->mEISAttr.iGyroFreq; pVideoEISData->mGyroAttr.axi_num = pVideoEISData->mEISAttr.iGyroAxiNum; pVideoEISData->mGyroAttr.force_open = 0; pVideoEISData->mGyroAttr.proc_mth = TS_AVERAGE_PROC; pVideoEISData->mGyroAttr.rb_len = pVideoEISData->mEISAttr.iGyroPoolSize; } ERRORTYPE VideoEISComponentInit(PARAM_IN COMP_HANDLETYPE hComponent) { int i = 0; ERRORTYPE eError = SUCCESS; MM_COMPONENTTYPE *pComp = (MM_COMPONENTTYPE *)hComponent; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)malloc(sizeof(VIDEOEISDATATYPE)); memset(pVideoEISData, 0x0, sizeof(VIDEOEISDATATYPE)); pComp->pComponentPrivate = (void *)pVideoEISData; pVideoEISData->state = COMP_StateLoaded; pthread_mutex_init(&pVideoEISData->mStateLock, NULL); pthread_mutex_init(&pVideoEISData->mEISLock, NULL); pthread_mutex_init(&pVideoEISData->mInputFrmLock, NULL); pVideoEISData->hSelf = hComponent; cdx_sem_init(&pVideoEISData->mSemWaitOutFrame, 0); /* Fill callback function pointers */ pComp->SetCallbacks = VideoEISSetCallbacks; pComp->SendCommand = VideoEISSendCommand; pComp->GetConfig = VideoEISGetConfig; pComp->SetConfig = VideoEISSetConfig; pComp->GetState = VideoEISGetState; pComp->ComponentTunnelRequest = VideoEISComponentTunnelRequest; pComp->ComponentDeInit = VideoEISComponentDeInit; pComp->EmptyThisBuffer = VideoEISEmptyThisBuffer; pComp->FillThisBuffer = VideoEISFillThisBuffer; /* Initialize component data structures to default values */ pVideoEISData->sPortParam.nPorts = 0; pVideoEISData->sPortParam.nStartPortNumber = 0x0; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].bEnabled = TRUE; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].eDomain = COMP_PortDomainVideo; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].eDir = COMP_DirInput; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].format.video.cMIMEType = "YVU420"; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].format.video.nFrameWidth = 176; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].format.video.nFrameHeight = 144; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].format.video.eCompressionFormat = PT_BUTT; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_VIDEO_IN].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_VIDEO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_VIDEO_IN].eBufferSupplier = COMP_BufferSupplyOutput; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_VIDEO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_VIDEO_IN].eTunnelType = TUNNEL_TYPE_COMMON; pVideoEISData->sPortParam.nPorts++; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].bEnabled = TRUE; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].eDomain = COMP_PortDomainVideo; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].eDir = COMP_DirInput; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].format.video.cMIMEType = "YVU420"; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].format.video.nFrameWidth = 176; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].format.video.nFrameHeight = 144; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].format.video.eCompressionFormat = PT_BUTT; // YCbCr420; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_GYRO_IN].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_GYRO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_GYRO_IN].eBufferSupplier = COMP_BufferSupplyOutput; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_GYRO_IN].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_GYRO_IN].eTunnelType = TUNNEL_TYPE_COMMON; pVideoEISData->sPortParam.nPorts++; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].bEnabled = TRUE; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].eDomain = COMP_PortDomainVideo; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].eDir = COMP_DirOutput; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].format.video.cMIMEType = "YVU420"; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].format.video.nFrameWidth = 176; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].format.video.nFrameHeight = 144; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].format.video.eCompressionFormat = PT_BUTT; // YCbCr420; pVideoEISData->sPortDef[EIS_CHN_PORT_INDEX_OUT].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_OUT].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortBufSupplier[EIS_CHN_PORT_INDEX_OUT].eBufferSupplier = COMP_BufferSupplyOutput; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_OUT].nPortIndex = pVideoEISData->sPortParam.nPorts; pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_OUT].eTunnelType = TUNNEL_TYPE_COMMON; pVideoEISData->sPortParam.nPorts++; /* EIS attribution initialize */ _EisInitAttrs(pVideoEISData); if (message_create(&pVideoEISData->cmd_queue) < 0) { aloge("message error!"); eError = ERR_VI_NOMEM; goto ECrtMsg; } /* Create the component thread to do video stabilization * the question is: should we open the gyro after create the gyro thread immediately? no. */ if (pthread_create(&pVideoEISData->mEISTrd, NULL, EIS_CompStabThread, pVideoEISData)) { aloge("create EIS_CompStabThread fail!"); eError = ERR_VI_NOMEM; goto ECrtStab; } alogv("VideoEIS component Init success!"); return SUCCESS; ECrtStab: message_destroy(&pVideoEISData->cmd_queue); ECrtMsg: free(pVideoEISData); return eError; } ERRORTYPE VideoEISComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent) { VIDEOEISDATATYPE *pVideoEISData; message_t msg; struct list_head *pList; ERRORTYPE eError = SUCCESS; int cnt = 0; if (NULL == hComponent) { aloge("Fatel error: NULL pointer."); return ERR_EIS_NOT_PERM; } pVideoEISData = (VIDEOEISDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); CompInternalMsgType eCmd = Stop; msg.command = eCmd; put_message(&pVideoEISData->cmd_queue, &msg); pthread_join(pVideoEISData->mEISTrd, (void *)&eError); message_destroy(&pVideoEISData->cmd_queue); pthread_mutex_destroy(&pVideoEISData->mInputFrmLock); pthread_mutex_destroy(&pVideoEISData->mStateLock); pthread_mutex_destroy(&pVideoEISData->mEISLock); cdx_sem_deinit(&pVideoEISData->mSemWaitOutFrame); free(pVideoEISData); pVideoEISData = NULL; alogv("VideoEIS component exited!"); return eError; } void _GyroDebugDumpAllChannelInfos(struct gyro_device_attr *gyro_attr) { int i = 0; for (i = 0; i < gyro_attr->arry_elems; i++) { printf("Channel [%d]:\r\n", i); printf("\tName\t%s\r\n", gyro_attr->iio_chn[i].name); printf("\tGName\t%s\r\n", gyro_attr->iio_chn[i].generic_name); printf("\tScale\t%f\r\n", gyro_attr->iio_chn[i].scale); printf("\toffset\t%f\r\n", gyro_attr->iio_chn[i].offset); printf("\tindex\t%u\r\n", gyro_attr->iio_chn[i].index); printf("\tbytes\t%u\r\n", gyro_attr->iio_chn[i].bytes); printf("\tbitused\t%u\r\n", gyro_attr->iio_chn[i].bits_used); printf("\tshift\t%u\r\n", gyro_attr->iio_chn[i].shift); printf("\tbe\t%u\r\n", gyro_attr->iio_chn[i].be); printf("\tis_sign\t%u\r\n", gyro_attr->iio_chn[i].is_signed); printf("\tlocation\t%u\r\n\n", gyro_attr->iio_chn[i].location); } } static void *EIS_CompGyroThread(void *pThreadData) { VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)pThreadData; int iGyroReadGrainSize = pVideoEISData->mEISAttr.iGyroFreq/pVideoEISData->mEISAttr.iVideoFps; int iGyroReadTimeIntervalUs = (1000/pVideoEISData->mEISAttr.iVideoFps)/2*1000; int iRet = 0; message_t cmd_msg; alogv("VideoEIS ComponentGyroThread start run..."); prctl(PR_SET_NAME, "EIS_CompGyroThread", 0, 0, 0); #if 0 int ret = 0; cpu_set_t stCpuSet; memset(&stCpuSet, 0, sizeof(cpu_set_t)); CPU_ZERO(&stCpuSet); CPU_SET(3, &stCpuSet); ret = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &stCpuSet); if (ret < 0) { aloge("sched_setaffinity failed!!\r\n"); } alogv("sched_setaffinity for GyroHw_CapThread\r\n"); #endif #if 0 struct sched_param stSchedPara; stSchedPara.sched_priority = 1; sched_setscheduler(syscall(__NR_gettid), SCHED_RR, &stSchedPara); // sched_setparam(syscall(__NR_gettid), const struct sched_param *param); alogv("loop GyroHw_CapThread, freq:%d, one read sequence gyro number:%d.\r\n", pVideoEISData->mEISAttr.iGyroFreq, iGyroReadGrainSize); // _GyroDebugDumpAllChannelInfos(&pVideoEISData->mGyroAttr); #endif while (pVideoEISData->bGyroRunFlag) { #if 0 fd_set stRdFdSet; struct timeval stTimeLimit; FD_ZERO(&stRdFdSet); FD_SET(pVideoEISData->mGyroAttr.gyro_fd, &stRdFdSet); stTimeLimit.tv_sec = 2; stTimeLimit.tv_usec = 0; iRet = select(pVideoEISData->mGyroAttr.gyro_fd + 1, &stRdFdSet, NULL, NULL, &stTimeLimit); if (iRet < 0) { aloge("Select wait for gyro datas failed, return %d.", -errno); continue; } else if (0 == iRet) { aloge("Select wait for gyro datas timeout."); continue; } iRet = _GyroHw_ReadParseRawDatas(pVideoEISData->GryoRingBufHd, &pVideoEISData->mGyroAttr, iGyroReadGrainSize, pVideoEISData->mEISAttr.iVideoFps); if (iRet == 0) { continue; } #endif if (pVideoEISData->bByPassMode && pVideoEISData->state == COMP_StateExecuting) { int i = 0; char pBufferTmp[4096]; int iStrLen = 0; for (i = 0; i < iGyroReadGrainSize; i++) { EIS_GYRO_PACKET_S stGyroPktOut; if (0 == ring_buffer_out(pVideoEISData->GryoRingBufHd, &stGyroPktOut, 1)) break; iStrLen = sprintf(&pBufferTmp[0], "%llu %f %f %f\n", stGyroPktOut.dTimeStamp, stGyroPktOut.fAnglrVX, stGyroPktOut.fAnglrVY, stGyroPktOut.fAnglrVZ); pBufferTmp[iStrLen] = '\0'; fwrite(&pBufferTmp[0], iStrLen, 1, pVideoEISData->pGyroPtsDataFd); } } /* Do not read too frequently */ usleep(iGyroReadTimeIntervalUs/2); } return NULL; } #if 1 static inline void _DumpGyroDatas2File (VIDEOEISDATATYPE *pVideoEISData, void *pstGyroData, bool bFloatTs) { #ifdef DEBUG_GYRO_BUFFER int iRet = 0; char pBufferTmp[4096]; char *pTmp = &pBufferTmp[0]; EIS_GYRO_PACKET_S *pstGyroPkt = (EIS_GYRO_PACKET_S *)pstGyroData; if (bFloatTs) iRet = sprintf(pTmp, "%lf %f %f %f\n", (double)pstGyroPkt->dTimeStamp/1000000.0f, pstGyroPkt->fAnglrVX, pstGyroPkt->fAnglrVY, pstGyroPkt->fAnglrVZ); else iRet = sprintf(pTmp, "%llu %f %f %f\n", pstGyroPkt->dTimeStamp, pstGyroPkt->fAnglrVX, pstGyroPkt->fAnglrVY, pstGyroPkt->fAnglrVZ); fwrite(&pBufferTmp[0], 1, iRet, pBufferInfo[pVideoEISData->mMppChnInfo.mChnId]); pTmp = &pBufferTmp[0]; #endif return; } /* * Tsv Tsv * Texp / / * *---------* *---------* * |*---------* *---------* * | *---------* *---------* * | *---------* *---------* * | | * Pn(pack gyro data number, equal to [iVideoLineTime]) */ static EISE_FrameData* _SyncAndPacketEisHardwareBuffer (VIDEOEISDATATYPE *pVideoEISData, VIDEO_FRAME_S *pstVFrm) { int i = 0; int iCurPktIdx = 0; EISE_FrameData *pstEISFrmTmp = NULL; struct ring_buffer* pGyroRBHd = pVideoEISData->GryoRingBufHd; #if 1 /* We must can find one, do not worry it will be failure. */ for (i = 0; i < pVideoEISData->mEISAttr.iInputBufNum; i++) { if (!(pVideoEISData->mEisPktMap & (1 << i))) { pstEISFrmTmp = &pVideoEISData->pstEISPkt[i]; pVideoEISData->mEisPktMap |= (1 << i); iCurPktIdx = i; break; } } #endif int iRet = 0; unsigned int iAbsOfGyroAndVideoTs = 0; /* Unit: ms */ EIS_GYRO_PACKET_S stGyroPkt; /* Use delay time to fix video data's timestamp. */ uint64_t dFixedVideoPts = 0; /* Unit: us */ uint64_t dVideoFrameIntervalMs = 1000/pVideoEISData->mEISAttr.iVideoFps; /* Unit: ms */ uint64_t dPacktEndTimeStamp = 0, dPacktStartTimeStamp = 0; /* Unit: us */ uint64_t dGyroIntervalUs = 1000000/pVideoEISData->mGyroAttr.sample_freq; uint64_t dGyroDataExtendIntervalUs = 0; int iNeedGyroDataNum = pVideoEISData->mGyroAttr.sample_freq/pVideoEISData->mEISAttr.iVideoFps; int iFixedDelayTime = 0; if (pstVFrm->mExposureTime > dVideoFrameIntervalMs) pstVFrm->mExposureTime = dVideoFrameIntervalMs; /* We use the half of exposure time te be the end of packet node. */ iFixedDelayTime = pVideoEISData->mEISAttr.iDelayTimeMs + pstVFrm->mExposureTime/2; dFixedVideoPts = (iFixedDelayTime > 0) ? pstVFrm->mpts - iFixedDelayTime*1000 : pstVFrm->mpts + abs(iFixedDelayTime)*1000; // printf("EIS:[%u]\n", pstVFrm->mExposureTime); dPacktEndTimeStamp = dFixedVideoPts - dVideoFrameIntervalMs*1000 + (uint64_t)(pVideoEISData->mEisCfg.td*1000000.0f); dPacktStartTimeStamp = dPacktEndTimeStamp - dVideoFrameIntervalMs*1000; #ifdef DEBUG_GYRO_BUFFER char pBufferTmp[4096]; char *pTmp = &pBufferTmp[0]; iRet = sprintf(pTmp, "Get one video pst[%lld], fixed[%lld], exp_time %u", pstVFrm->mpts, dPacktStartTimeStamp, pstVFrm->mExposureTime); pTmp += iRet; *pTmp++ = '\n'; fwrite(&pBufferTmp[0], 1, (pTmp-&pBufferTmp[0]), pBufferInfo[pVideoEISData->mMppChnInfo.mChnId]); pTmp = &pBufferTmp[0]; #endif i = 0; while (1) { /* First of all, we will past the all old gyro data packets, * find the nextest start one gyro data with timestamp. */ if (ring_buffer_out(pGyroRBHd, &stGyroPkt, 1) <= 0) goto EEmptyRB; _DumpGyroDatas2File(pVideoEISData, &stGyroPkt, 1); /* The oldest gyro data value is too fresh, * even it is low probability, but we still catch it. */ if (stGyroPkt.dTimeStamp >= dPacktEndTimeStamp) goto EEmptyRB; iAbsOfGyroAndVideoTs = llabs(dPacktStartTimeStamp - stGyroPkt.dTimeStamp); if (iAbsOfGyroAndVideoTs <= pVideoEISData->mEISAttr.iSyncErrTolerance*1000 || stGyroPkt.dTimeStamp >= dPacktStartTimeStamp) { pstEISFrmTmp->gyro_data[i].time = stGyroPkt.dTimeStamp; pstEISFrmTmp->gyro_data[i].ax = stGyroPkt.fAccelVX*pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor; pstEISFrmTmp->gyro_data[i].ay = stGyroPkt.fAccelVY*pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor; pstEISFrmTmp->gyro_data[i].az = stGyroPkt.fAccelVZ*pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor; pstEISFrmTmp->gyro_data[i].vx = stGyroPkt.fAnglrVX*pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor; pstEISFrmTmp->gyro_data[i].vy = stGyroPkt.fAnglrVY*pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor; pstEISFrmTmp->gyro_data[i].vz = stGyroPkt.fAnglrVZ*pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor; _DumpGyroDatas2File(pVideoEISData, &stGyroPkt, 0); pstEISFrmTmp->gyro_data[i].vx -= pVideoEISData->mEisCfg.stable_anglev[0]*pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor; pstEISFrmTmp->gyro_data[i].vy -= pVideoEISData->mEisCfg.stable_anglev[1]*pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor; pstEISFrmTmp->gyro_data[i].vz -= pVideoEISData->mEisCfg.stable_anglev[2]*pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor; break; } } i++; while (1) { /* If we got one gyro packet success, * then use it whatever, even it may not too valid. */ if (ring_buffer_out(pGyroRBHd, &stGyroPkt, 1) <= 0) { aloge("Empty."); goto EEmptyRB; } pstEISFrmTmp->gyro_data[i].time = stGyroPkt.dTimeStamp; pstEISFrmTmp->gyro_data[i].ax = stGyroPkt.fAccelVX*pVideoEISData->mEisPrivAttr.fGyroAxScaleFactor; pstEISFrmTmp->gyro_data[i].ay = stGyroPkt.fAccelVY*pVideoEISData->mEisPrivAttr.fGyroAyScaleFactor; pstEISFrmTmp->gyro_data[i].az = stGyroPkt.fAccelVZ*pVideoEISData->mEisPrivAttr.fGyroAzScaleFactor; pstEISFrmTmp->gyro_data[i].vx = stGyroPkt.fAnglrVX*pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor; pstEISFrmTmp->gyro_data[i].vy = stGyroPkt.fAnglrVY*pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor; pstEISFrmTmp->gyro_data[i].vz = stGyroPkt.fAnglrVZ*pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor; _DumpGyroDatas2File(pVideoEISData, &stGyroPkt, 0); pstEISFrmTmp->gyro_data[i].vx -= pVideoEISData->mEisCfg.stable_anglev[0]*pVideoEISData->mEisPrivAttr.fGyroVxScaleFactor; pstEISFrmTmp->gyro_data[i].vy -= pVideoEISData->mEisCfg.stable_anglev[1]*pVideoEISData->mEisPrivAttr.fGyroVyScaleFactor; pstEISFrmTmp->gyro_data[i].vz -= pVideoEISData->mEisCfg.stable_anglev[2]*pVideoEISData->mEisPrivAttr.fGyroVzScaleFactor; i++; /* Keep one newest timestamp for the next sync */ if (dPacktEndTimeStamp < stGyroPkt.dTimeStamp || (i >= sizeof(pstEISFrmTmp->gyro_data)/sizeof(pstEISFrmTmp->gyro_data[0]))) break; // We got enough datas } EEmptyRB: pVideoEISData->iGVSyncPktId++; if (i == 0) { if (NULL == pVideoEISData->pLastUsedEISPkt) { /* This mean we got an empty buffer packets, construct it. */ aloge("Got zero gyro buffer datas. video pts[%llu], construct it.", pstVFrm->mpts); memset(&pstEISFrmTmp->gyro_data[0], 0, sizeof(pstEISFrmTmp->gyro_data)); pstEISFrmTmp->gyro_data[0].time = dPacktStartTimeStamp; dGyroDataExtendIntervalUs = (dPacktEndTimeStamp - dPacktStartTimeStamp)/(iNeedGyroDataNum-1); pstEISFrmTmp->gyro_data[0].ax = 0.0f; pstEISFrmTmp->gyro_data[0].ay = 0.0f; pstEISFrmTmp->gyro_data[0].az = 0.0f; pstEISFrmTmp->gyro_data[0].vx = 0.0f;//-0.005f; pstEISFrmTmp->gyro_data[0].vy = 0.0f;//-0.002f; pstEISFrmTmp->gyro_data[0].vz = 0.0f;//0.004f; _DumpGyroDatas2File(pVideoEISData, &pstEISFrmTmp->gyro_data[0], 0); while (1) { i++; pstEISFrmTmp->gyro_data[i].time = pstEISFrmTmp->gyro_data[i-1].time + dGyroDataExtendIntervalUs; pstEISFrmTmp->gyro_data[i].ax = 0; pstEISFrmTmp->gyro_data[i].ay = 0; pstEISFrmTmp->gyro_data[i].az = 0; pstEISFrmTmp->gyro_data[i].vx = 0.0f;//-0.005f; pstEISFrmTmp->gyro_data[i].vy = 0.0f;//-0.002f; pstEISFrmTmp->gyro_data[i].vz = 0.0f;//0.004f; _DumpGyroDatas2File(pVideoEISData, &pstEISFrmTmp->gyro_data[i], 0); if (pstEISFrmTmp->gyro_data[i].time > dPacktEndTimeStamp) break; } } else { if (pVideoEISData->bHasGyroDev && pVideoEISData->iGVSyncPktId % pVideoEISData->mEISAttr.iVideoFps == 0) /* This mean we got an empty buffer packets. then use the last gyro data one */ aloge("Got zero gyro buffer datas. video pts[%llu], last pts[%llu], ring buffer kepp[%d].", pstVFrm->mpts, pVideoEISData->pLastUsedEISPkt->gyro_data[pVideoEISData->pLastUsedEISPkt->gyro_num-1].time, ring_buffer_g_validnum(pGyroRBHd)); /* Copy all old gyro buffers, and change its timestamps */ memcpy(&pstEISFrmTmp->gyro_data[0], &pVideoEISData->pLastUsedEISPkt->gyro_data[0], sizeof(pstEISFrmTmp->gyro_data)); pstEISFrmTmp->gyro_num = pVideoEISData->pLastUsedEISPkt->gyro_num; pstEISFrmTmp->gyro_data[0].time = dPacktStartTimeStamp; dGyroDataExtendIntervalUs = (dPacktEndTimeStamp - dPacktStartTimeStamp)/(pstEISFrmTmp->gyro_num-1); if (pVideoEISData->bHasGyroDev && pVideoEISData->iGVSyncPktId % pVideoEISData->mEISAttr.iVideoFps == 0) aloge("Got zero gyro buffer datas. video pts0[%llu], num[%d].", pstEISFrmTmp->gyro_data[0].time, pstEISFrmTmp->gyro_num); /* Fix timestamps */ while (1) { i++; pstEISFrmTmp->gyro_data[i].time = pstEISFrmTmp->gyro_data[i-1].time + dGyroDataExtendIntervalUs; if (pstEISFrmTmp->gyro_data[i].time > dPacktEndTimeStamp) break; } } } else if (i < iNeedGyroDataNum/4) { // TODO: /* Too less packets, shoudle we use the last one? */ /* Should copy the last gyro data to pad the gyro data number, but increase timestamp */ /* Just keep the exist program, if can not support, then change it. */ aloge("Too less gyro buffer datas %d, ring buffer keep[%d], then extend to %d datas.\n", i, ring_buffer_g_validnum(pGyroRBHd), iNeedGyroDataNum); #if 0 dGyroDataExtendIntervalUs = (dPacktEndTimeStamp - pstEISFrmTmp->gyro_data[i-1].time)/(iNeedGyroDataNum-i); for (; i < iNeedGyroDataNum; i++) { pstEISFrmTmp->gyro_data[i].time = pstEISFrmTmp->gyro_data[i-1].time + dGyroDataExtendIntervalUs; pstEISFrmTmp->gyro_data[i].ax = pstEISFrmTmp->gyro_data[i-1].ax; pstEISFrmTmp->gyro_data[i].ay = pstEISFrmTmp->gyro_data[i-1].ay; pstEISFrmTmp->gyro_data[i].az = pstEISFrmTmp->gyro_data[i-1].az; pstEISFrmTmp->gyro_data[i].vx = pstEISFrmTmp->gyro_data[i-1].vx; pstEISFrmTmp->gyro_data[i].vy = pstEISFrmTmp->gyro_data[i-1].vy; pstEISFrmTmp->gyro_data[i].vz = pstEISFrmTmp->gyro_data[i-1].vz; } #endif } pVideoEISData->pLastUsedEISPkt = pstEISFrmTmp; pVideoEISData->dLastInputFrmPts = dPacktEndTimeStamp; pstEISFrmTmp->frame_stamp = dPacktEndTimeStamp; pstEISFrmTmp->gyro_num = i; #ifdef DEBUG_GYRO_BUFFER iRet = sprintf(pTmp, "We got video timestamp[%llu], gyro_num[%d]", pstEISFrmTmp->frame_stamp, i); pTmp += iRet; *pTmp++ = '\n'; fwrite(&pBufferTmp[0], 1, (pTmp-&pBufferTmp[0]), pBufferInfo[pVideoEISData->mMppChnInfo.mChnId]); pTmp = &pBufferTmp[0]; if (i < iNeedGyroDataNum/2 || i > iNeedGyroDataNum*3/2) { iRet = sprintf(pTmp, "Toooooooo small or long data num[%d]", i); pTmp += iRet; *pTmp++ = '\n'; fwrite(&pBufferTmp[0], 1, (pTmp-&pBufferTmp[0]), pBufferInfo[pVideoEISData->mMppChnInfo.mChnId]); pTmp = &pBufferTmp[0]; } #endif return pstEISFrmTmp; } #endif static void *EIS_CompStabThread(void *pThreadData) { unsigned int cmddata; CompInternalMsgType cmd; VIDEOEISDATATYPE *pVideoEISData = (VIDEOEISDATATYPE *)pThreadData; COMP_INTERNAL_TUNNELINFOTYPE *pOutputPort = &pVideoEISData->sPortTunnelInfo[EIS_CHN_PORT_INDEX_OUT]; message_t cmd_msg; ERRORTYPE eError = 0; int iRet = 0; #if 1 if (pVideoEISData->mEISAttr.eOperationMode != EIS_OPR_VGA30 && pVideoEISData->mEISAttr.eOperationMode != EIS_OPR_VGA60) { struct sched_param stSchedPara; stSchedPara.sched_priority = 20; if (pthread_setschedparam(pthread_self(), SCHED_RR, &stSchedPara)) aloge("Set EIS_CompStabThread into SCHED_RR failed, %s.", strerror(errno)); } #endif alogv("VideoEIS ComponentStabThread start run..."); prctl(PR_SET_NAME, "EIS_CompStabThread", 0, 0, 0); while (1) { PROCESS_MESSAGE: if (get_message(&pVideoEISData->cmd_queue, &cmd_msg) == 0) { cmd = cmd_msg.command; cmddata = (unsigned int)cmd_msg.para0; // alogv("VideoVi ComponentThread get_message cmd:%d", cmd); if (cmd == SetState) { pthread_mutex_lock(&pVideoEISData->mStateLock); if (pVideoEISData->state == (COMP_STATETYPE)(cmddata)) { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_SAMESTATE, 0, NULL); } else { switch ((COMP_STATETYPE)(cmddata)) { case COMP_StateInvalid: { pVideoEISData->state = COMP_StateInvalid; // CompSendEvent(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INVALIDSTATE, 0); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INVALIDSTATE, 0, NULL); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } break; case COMP_StateLoaded: { if (pVideoEISData->state != COMP_StateIdle) { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } pVideoEISData->mWaitAllFrameReleaseFlag = 1; DoVideoEisReturnBackAllInputFrames(pVideoEISData); if (!list_empty(&pVideoEISData->mOutUsedList)) { aloge("Wait EIS component output buffer used frame list empty."); while (!list_empty(&pVideoEISData->mOutUsedList)) {usleep(10*1000);}; } VideoBufMgrWaitUsingEmpty(pVideoEISData->pInputBufMgr); alogd("Wait all EIS component output using frame return done."); pVideoEISData->mWaitAllFrameReleaseFlag = 0; pVideoEISData->state = COMP_StateLoaded; _VideoEisDestroy(pVideoEISData); alogv("Set EIS OMX_StateLoaded OK"); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } break; case COMP_StateIdle: { if (pVideoEISData->state == COMP_StateLoaded) { alogv("video VI: loaded->idle ..."); pVideoEISData->state = COMP_StateIdle; pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } else if (pVideoEISData->state == COMP_StatePause || pVideoEISData->state == COMP_StateExecuting) { alogv("video vi: pause/executing[0x%x]->idle ...", pVideoEISData->state); //release all frames to video input. if(!VideoBufMgrUsingEmpty(pVideoEISData->pInputBufMgr)) { alogw("Fatal warning! using frame is not empty! check code!"); } pVideoEISData->state = COMP_StateIdle; alogv("Set EIS COMP_StateIdle OK"); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } else { aloge("Fatal error! current state[0x%x] can't turn to idle!", pVideoEISData->state); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } } break; case COMP_StateExecuting: { // Transition can only happen from pause or idle state if (pVideoEISData->state == COMP_StateIdle || pVideoEISData->state == COMP_StatePause) { eError = _VideoEisCreate(pVideoEISData); if (SUCCESS != eError) { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, COMP_CommandStateSet, eError, NULL); aloge("Convert status Idle->Executing failed because open hw EIS failed. ret 0x%x.", eError); } else { pVideoEISData->state = COMP_StateExecuting; alogv("Set Virvi COMP_StateExecuting OK"); pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } } else { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } } break; case COMP_StatePause: { /* Transition can only happen from idle or executing state */ if (pVideoEISData->state == COMP_StateIdle || pVideoEISData->state == COMP_StateExecuting) { pVideoEISData->state = COMP_StatePause; pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoEISData->state, NULL); } else { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } } break; default: break; } } pthread_mutex_unlock(&pVideoEISData->mStateLock); } else if (cmd == Flush) { pVideoEISData->pCallbacks->EventHandler(pVideoEISData->hSelf, pVideoEISData->pAppData, COMP_EventCmdComplete, COMP_CommandFlush, 0, NULL); } else if (cmd == Stop) { /* Kill thread */ goto EXIT; } else if(cmd == EisComp_InputFrameAvailable) { alogv("(f:%s, l:%d) frame input", __FUNCTION__, __LINE__); } else if(cmd == EisComp_StoreFrame) { pVideoEISData->bStoreFrame = TRUE; snprintf(pVideoEISData->mDbgStoreFrameFilePath, sizeof(pVideoEISData->mDbgStoreFrameFilePath), "%s", (char*)cmd_msg.mpData); /* mpData is malloced in TMessageDeepCopyMessage() */ free(cmd_msg.mpData); cmd_msg.mpData = NULL; cmd_msg.mDataSize = 0; } //precede to process message goto PROCESS_MESSAGE; } int eError; if (pVideoEISData->state == COMP_StateExecuting) { int iInputFrmId = 0; /* Find one input buffer from input buffer list, do gyro sync * and fetch one output buffer from output buffer list. */ /* Get one video buffer and do one sync operation. check if sync successful. * 1.if there has no gyro data can be synced, then use the last one. */ VIDEO_FRAME_INFO_S *pVInFrm; pVInFrm = VideoBufMgrGetValidFrame(pVideoEISData->pInputBufMgr); if (NULL == pVInFrm) { /* Maybe this thread was cut out, and [VideoBufMgrPushFrame] was invoked, * but the [pVideoEISData->bWaitingInputFrmFlag] was not set, * then this thread will be get into stall. so after set [bWaitingInputFrmFlag], * check if we haven't got valid buffer yet, if not, then just sleep, do not worry it will be stall. */ pVideoEISData->bWaitingInputFrmFlag = TRUE; pVInFrm = VideoBufMgrGetValidFrame(pVideoEISData->pInputBufMgr); if (NULL == pVInFrm) { TMessage_WaitQueueNotEmpty(&pVideoEISData->cmd_queue, 0); pVideoEISData->bWaitingInputFrmFlag = FALSE; goto PROCESS_MESSAGE; } else pVideoEISData->bWaitingInputFrmFlag = FALSE; } VIDEO_FRAME_INFO_S *pVideoInBufTmp = NULL; VIDEO_FRAME_INFO_S stVideoInBufRetTmp; /* If is bypass mode, then save all datas in specific path. */ if (pVideoEISData->bByPassMode) { static uint64_t dCacheFrmCnt = 0; EIS_GYRO_PACKET_S stGyroPkt; char pBufferTmp[4096]; int iStrLen = 0; pVideoInBufTmp = VideoBufMgrGetSpecUsingFrameWithAddr( pVideoEISData->pInputBufMgr, pVInFrm->VFrame.mpVirAddr[0]); if (pVideoInBufTmp) { pVideoEISData->iCacheBufferNum++; iStrLen = sprintf(&pBufferTmp[0], "%llu %u %d\n", pVideoInBufTmp->VFrame.mpts, pVideoInBufTmp->VFrame.mExposureTime, pVideoEISData->iCacheBufferNum); pBufferTmp[iStrLen] = '\0'; fwrite(&pBufferTmp[0], iStrLen, 1, pVideoEISData->pVideoPtsFd); if (pVideoEISData->mEISAttr.bSaveYUV) { fwrite(pVideoInBufTmp->VFrame.mpVirAddr[0], pVideoInBufTmp->VFrame.mHeight*pVideoInBufTmp->VFrame.mWidth, 1, pVideoEISData->pVideoDataFd); fwrite(pVideoInBufTmp->VFrame.mpVirAddr[1], pVideoInBufTmp->VFrame.mHeight*pVideoInBufTmp->VFrame.mWidth/2, 1, pVideoEISData->pVideoDataFd); } else { VideoFrameListInfo *pVFrmOutputCur; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); pVFrmOutputCur = list_first_entry(&pVideoEISData->mOutIdleList, VideoFrameListInfo, mList); ion_flushCache(pVideoInBufTmp->VFrame.mpVirAddr[0], pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight); ion_flushCache(pVideoInBufTmp->VFrame.mpVirAddr[1], pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight/2); /* If we only have one output idle video frame, then keep it. */ if (pVideoEISData->iOutFrmIdleCnt > 1) { list_move_tail(&pVFrmOutputCur->mList, &pVideoEISData->mOutValidList); pVideoEISData->iOutFrmIdleCnt--; } else aloge("We has only one idle frame in EIS output frame list."); pVFrmOutputCur->mFrame.VFrame.mPhyAddr[0] = pVideoInBufTmp->VFrame.mPhyAddr[0]; pVFrmOutputCur->mFrame.VFrame.mPhyAddr[1] = pVideoInBufTmp->VFrame.mPhyAddr[1]; pVFrmOutputCur->mFrame.VFrame.mpts = pVideoInBufTmp->VFrame.mpts; pVFrmOutputCur->mFrame.VFrame.mExposureTime = pVideoInBufTmp->VFrame.mExposureTime; #if 1 #define POINT_BEGINX 100 #define POINT_BEGINY 50 #define POINT_SIZE 3 #define POINT_LINE_LEN 40 #define POINT_GRP_SIZE 5 { int i = 0, j = 0, k = 0; char *pDrawPosBegin = (char *)pVideoInBufTmp->VFrame.mpVirAddr[0] + pVideoInBufTmp->VFrame.mWidth*POINT_BEGINY+POINT_BEGINX; char *pDrawPos = NULL; for (i = 0; i < pVideoEISData->iCacheBufferNum; i++) { pDrawPos = pDrawPosBegin + (i/POINT_LINE_LEN)*POINT_SIZE*2*pVideoInBufTmp->VFrame.mWidth + (i%POINT_LINE_LEN)*POINT_SIZE*2 + (i%POINT_LINE_LEN/POINT_GRP_SIZE*POINT_SIZE); for (j = 0; j < POINT_SIZE; j++) { for (k = 0; k < POINT_SIZE; k++) { pDrawPos[j*pVideoInBufTmp->VFrame.mWidth+k] = ~pDrawPos[j*pVideoInBufTmp->VFrame.mWidth+k]; } } } ion_flushCache(pVideoInBufTmp->VFrame.mpVirAddr[0], pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight); ion_flushCache(pVideoInBufTmp->VFrame.mpVirAddr[1], pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight/2); } #endif pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); if (pVideoEISData->bWaitingOutFrmFlag && pVideoEISData->iOutFrmIdleCnt >= 1) cdx_sem_up(&pVideoEISData->mSemWaitOutFrame); } /* Return input buffer to last component, must invoke [DoVideoEisSendBackInputFrame] first */ stVideoInBufRetTmp = *pVideoInBufTmp; VideoBufMgrReleaseFrame(pVideoEISData->pInputBufMgr, pVideoInBufTmp); DoVideoEisSendBackInputFrame(pVideoEISData, &stVideoInBufRetTmp); } goto PROCESS_MESSAGE; } VideoFrameListInfo *pVFrmOutputCur; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); pVFrmOutputCur = list_first_entry(&pVideoEISData->mOutIdleList, VideoFrameListInfo, mList); // ion_flushCache(pVFrmOutputCur->mFrame.VFrame.mpVirAddr[0], // pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight); // ion_flushCache(pVFrmOutputCur->mFrame.VFrame.mpVirAddr[1], // pVFrmOutputCur->mFrame.VFrame.mWidth*pVFrmOutputCur->mFrame.VFrame.mHeight/2); pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); /* Set the next output address. */ EIS_PROCOUT_PARA stOutputPara; memset(&stOutputPara, 0, sizeof(EIS_PROCOUT_PARA)); stOutputPara.out_luma_mmu_Addr = pVFrmOutputCur->mFrame.VFrame.mpVirAddr[0]; stOutputPara.out_luma_phy_Addr = pVFrmOutputCur->mFrame.VFrame.mPhyAddr[0]; stOutputPara.out_chroma_u_mmu_Addr = pVFrmOutputCur->mFrame.VFrame.mpVirAddr[1]; stOutputPara.out_chroma_u_phy_Addr = pVFrmOutputCur->mFrame.VFrame.mPhyAddr[1]; EIS_setOutputAddr(&pVideoEISData->mEisHd, &stOutputPara); EISE_FrameData* pEisProcPkt; int iEisProcRet = 0; pEisProcPkt = _SyncAndPacketEisHardwareBuffer(pVideoEISData, &pVInFrm->VFrame); // pEisProcPkt->frame_stamp = pVInFrm->VFrame.mpts; pEisProcPkt->texp = (float)pVInFrm->VFrame.mExposureTime/1000.0f; // aloge("Send video pts: %f %f gyro_num[%d] %f %f %f %f to process.", // pEisProcPkt->frame_stamp, pEisProcPkt->texp, pEisProcPkt->gyro_num, pEisProcPkt->gyro_data[0].time, // pEisProcPkt->gyro_data[0].vx, pEisProcPkt->gyro_data[0].vy, pEisProcPkt->gyro_data[0].vz); pEisProcPkt->in_addr.in_luma_mmu_Addr = pVInFrm->VFrame.mpVirAddr[0]; pEisProcPkt->in_addr.in_luma_phy_Addr = pVInFrm->VFrame.mPhyAddr[0]; pEisProcPkt->in_addr.in_chroma_mmu_Addr = pVInFrm->VFrame.mpVirAddr[1]; pEisProcPkt->in_addr.in_chroma_phy_Addr = pVInFrm->VFrame.mPhyAddr[1]; #if 0 static unsigned long long iSelfProcTest = 0; if (iSelfProcTest >= pVideoEISData->mEISAttr.iInputBufNum-3) { iGetFrmId = iSelfProcTest % (pVideoEISData->mEISAttr.iInputBufNum-3); iEisProcRet = LIB_S_OK; } else { iEisProcRet = LIB_E_BUFFER_NOT_ENOUGH; } iSelfProcTest++; #else EIS_setFrameData(&pVideoEISData->mEisHd, pEisProcPkt); pVideoEISData->dEisGetInputFrmCnt++; if (pVideoEISData->mEISAttr.bRetInFrmFast && pVideoEISData->dEisGetInputFrmCnt >= pVideoEISData->mEISAttr.iInputBufNum) { int i = 0; pVideoInBufTmp = VideoBufMgrGetOldestUsingFrame(pVideoEISData->pInputBufMgr); if (pVideoInBufTmp) { for (i = 0; i < pVideoEISData->mEISAttr.iInputBufNum; i++) { if (pVideoEISData->pstEISPkt[i].in_addr.in_luma_mmu_Addr == pVideoInBufTmp->VFrame.mpVirAddr[0]) { pVideoEISData->mEisPktMap &= ~(1 << i); break; } } /* Return input buffer to last component, must invoke [DoVideoEisSendBackInputFrame] first */ stVideoInBufRetTmp = *pVideoInBufTmp; VideoBufMgrReleaseFrame(pVideoEISData->pInputBufMgr, pVideoInBufTmp); DoVideoEisSendBackInputFrame(pVideoEISData, &stVideoInBufRetTmp); } else aloge("Using frame list empty."); } #ifdef PROC_TIME_TEST TIME_INIT_START_END(T); TIME_GET_START(T); #endif /* Send to kernel drivers and process it. */ iEisProcRet = EIS_Proc(&pVideoEISData->mEisHd, &iInputFrmId); #ifdef PROC_TIME_TEST TIME_GET_END(T); printf("[%d]%f.\n", pVideoEISData->mMppChnInfo.mChnId, TIME_PRINT_DIFF(T)); #endif #endif switch (iEisProcRet) { case LIB_S_OK: { /* We got one processed buffer */ pEisProcPkt = &pVideoEISData->pstEISPkt[iInputFrmId]; COMP_BUFFERHEADERTYPE obh; bool bCanGetOutBuf = 0; bCanGetOutBuf = 0; pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); /* If we only have one output idle video frame, then keep it */ if (pVideoEISData->iOutFrmIdleCnt > 1) { list_move_tail(&pVFrmOutputCur->mList, &pVideoEISData->mOutValidList); pVideoEISData->iOutFrmIdleCnt--; bCanGetOutBuf = 1; } else{ aloge("We has only one idle frame in EIS output frame list."); } pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); if (!pVideoEISData->mEISAttr.bRetInFrmFast) { pVideoInBufTmp = VideoBufMgrGetSpecUsingFrameWithAddr( pVideoEISData->pInputBufMgr, pEisProcPkt->in_addr.in_luma_mmu_Addr); if (pVideoInBufTmp) { /* Return input buffer to last component, must invoke [DoVideoEisSendBackInputFrame] first */ stVideoInBufRetTmp = *pVideoInBufTmp; VideoBufMgrReleaseFrame(pVideoEISData->pInputBufMgr, pVideoInBufTmp); DoVideoEisSendBackInputFrame(pVideoEISData, &stVideoInBufRetTmp); } else aloge("Not find input buffer in UsingFrameList, addr=0x%x.", pEisProcPkt->in_addr.in_luma_mmu_Addr); /* Now, clear using flag. */ pVideoEISData->mEisPktMap &= ~(1 << iInputFrmId); } /* If we find one processed success video frame, then push it to next component * or valid frame list. */ if (bCanGetOutBuf) { if (pVideoInBufTmp) pVFrmOutputCur->mFrame.VFrame.mpts = stVideoInBufRetTmp.VFrame.mpts; else pVFrmOutputCur->mFrame.VFrame.mpts = 0; if (FALSE == pVideoEISData->bOutputPortTunnelFlag) { if (pVideoEISData->bWaitingOutFrmFlag) cdx_sem_up(&pVideoEISData->mSemWaitOutFrame); } else if (TRUE == pVideoEISData->bOutputPortTunnelFlag && pOutputPort->hTunnel) { MM_COMPONENTTYPE *pOutTunnelComp = (MM_COMPONENTTYPE*)pOutputPort->hTunnel; VIDEO_FRAME_INFO_S* pVOutFrm = &pVFrmOutputCur->mFrame; pVOutFrm->VFrame.mOffsetTop = 0; pVOutFrm->VFrame.mOffsetBottom = pVOutFrm->VFrame.mHeight; pVOutFrm->VFrame.mOffsetLeft = 0; pVOutFrm->VFrame.mOffsetRight = pVOutFrm->VFrame.mWidth; if(pVideoEISData->bStoreFrame) { DoVideoEisStoreProcessedFrm(pVideoEISData, pVOutFrm); pVideoEISData->bStoreFrame = FALSE; } pthread_mutex_lock(&pVideoEISData->mOutFrmListLock); obh.nOutputPortIndex = pOutputPort->nPortIndex; obh.nInputPortIndex = pOutputPort->nTunnelPortIndex; obh.pOutputPortPrivate = pVOutFrm; eError = COMP_EmptyThisBuffer(pOutTunnelComp, &obh); if(SUCCESS != eError) { alogw("Loop EIS_CompStabThread OutTunnelComp EmptyThisBuffer failed 0x%x, return this frame", eError); /* Just return */ list_move_tail(&pVFrmOutputCur->mList, &pVideoEISData->mOutIdleList); pVideoEISData->iOutFrmIdleCnt++; } else list_move_tail(&pVFrmOutputCur->mList, &pVideoEISData->mOutUsedList); pthread_mutex_unlock(&pVideoEISData->mOutFrmListLock); } } else{ aloge("Not find output buffer."); } } break; case LIB_E_BUFFER_NOT_ENOUGH: { alogw("Has not get enough buffer."); } break; default: { /* Something error occurs, and we should return the oldest using frame. */ if (!pVideoEISData->mEISAttr.bRetInFrmFast) { int i = 0; pVideoInBufTmp = VideoBufMgrGetOldestUsingFrame(pVideoEISData->pInputBufMgr); if (pVideoInBufTmp) { for (i = 0; i < pVideoEISData->mEISAttr.iInputBufNum; i++) { if (pVideoEISData->pstEISPkt[i].in_addr.in_luma_mmu_Addr == pVideoInBufTmp->VFrame.mpVirAddr[0]) { pVideoEISData->mEisPktMap &= ~(1 << i); aloge("Free used EISPkt[%d] because of hardware error.", i); break; } } /* Return input buffer to last component, must invoke [DoVideoEisSendBackInputFrame] first */ stVideoInBufRetTmp = *pVideoInBufTmp; VideoBufMgrReleaseFrame(pVideoEISData->pInputBufMgr, pVideoInBufTmp); DoVideoEisSendBackInputFrame(pVideoEISData, &stVideoInBufRetTmp); } else aloge("Using frame list empty."); } aloge("Got one undefined error. ret 0x%x.", iEisProcRet); } break; } } else { alogv("EIS_CompStabThread not OMX_StateExecuting\n"); TMessage_WaitQueueNotEmpty(&pVideoEISData->cmd_queue, 0); } } EXIT: alogv("VideoEis ComponentThread stopped"); return (void *)SUCCESS; }