/****************************************************************************** Copyright (C), 2001-2016, Allwinner Tech. Co., Ltd. ****************************************************************************** File Name : VideoVi_Component.c Version : Initial Draft Author : Allwinner BU3-PD2 Team Created : 2016/05/09 Last Modified : Description : mpp component implement Function List : History : ******************************************************************************/ //#define LOG_NDEBUG 0 #define LOG_TAG "VideoVirVi_Component" #include //ref platform headers #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_vi.h" #include "mm_comm_video.h" #include #include "mm_common.h" #include "mpi_vi.h" #include "ComponentCommon.h" #include "media_common.h" #include "mm_component.h" #include "tmessage.h" #include "tsemaphore.h" #include "vencoder.h" // #include "../LIBRARY/libisp/include/device/csi_subdev.h" #include "VideoVirVi_Component.h" #include "isp_dev.h" #include "video.h" #include "video_buffer_manager.h" #include #include #include "../videoIn/videoInputHw.h" //#define VIDEO_ENC_TIME_DEBUG typedef struct awVIDEOVIDATATYPE{ COMP_STATETYPE state; pthread_mutex_t mStateLock; pthread_mutex_t mLock; COMP_CALLBACKTYPE* pCallbacks; void* pAppData; COMP_HANDLETYPE hSelf; char mThreadName[32]; COMP_PORT_PARAM_TYPE sPortParam; COMP_PARAM_PORTDEFINITIONTYPE sPortDef[VI_CHN_MAX_PORTS]; COMP_INTERNAL_TUNNELINFOTYPE sPortTunnelInfo[VI_CHN_MAX_PORTS]; COMP_PARAM_BUFFERSUPPLIERTYPE sPortBufSupplier[VI_CHN_MAX_PORTS]; bool mInputPortTunnelFlag; bool mOutputPortTunnelFlag; //TRUE: tunnel mode; FALSE: non-tunnel mode. MPP_CHN_S mMppChnInfo; VI_ATTR_S mViAttr; ViVirChnAttrS mViVirChnAttr; pthread_t thread_id; // CompInternalMsgType eTCmd; message_queue_t cmd_queue; volatile int mWaitingCapDataFlag; cdx_sem_t mAllFrameRelSem; volatile int mWaitAllFrameReleaseFlag; VideoBufferManager* mpCapMgr; pthread_mutex_t mFrameLock; cdx_sem_t mSemWaitInputFrame; VI_SHUTTIME_CFG_S mLongExp; int mSetLongExpCnt; int mLongExpFrameDelay; int mLongExpFrameCnt; pthread_mutex_t mLongExpLock; int mStoreFrameCount; char mDbgStoreFrameFilePath[VI_MAXPATHSIZE]; uint64_t mLastFrmPtsCache; unsigned int mLastFrmCnt; bool mbStoreFrame; } VIDEOVIDATATYPE; /* Used for async long exposure mode. */ enum awVI_LONGEXP_EVENT { E_VI_LONGEXP_SET, /* Set to long exposure mode. */ E_VI_LONGEXP_RESET, /* Reset from long exposure mode. */ }; static void *Vi_ComponentThread(void *pThreadData); static ERRORTYPE DoVideoViSendBackInputFrame(VIDEOVIDATATYPE *pVideoViData, VIDEO_FRAME_INFO_S *pFrameInfo) { COMP_BUFFERHEADERTYPE BufferHeader; BufferHeader.pOutputPortPrivate = pFrameInfo; if (FALSE == pVideoViData->mInputPortTunnelFlag) { pVideoViData->pCallbacks->EmptyBufferDone(pVideoViData->hSelf, pVideoViData->pAppData, &BufferHeader); } else { alogw("unsupported temporary: vda return input frame in tunnel mode!"); MM_COMPONENTTYPE *pTunnelComp = (MM_COMPONENTTYPE *)pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_CAP_IN].hTunnel; pTunnelComp->FillThisBuffer(pTunnelComp, &BufferHeader); } alogd("release input FrameId[%d]", pFrameInfo->mId); return SUCCESS; } ERRORTYPE DoVideoViGetPortDefinition(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_PARAM_PORTDEFINITIONTYPE *pPortDef) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; int i; for(i = 0; i < VI_CHN_MAX_PORTS; i++) { if (pPortDef->nPortIndex == pVideoViData->sPortDef[i].nPortIndex) { memcpy(pPortDef, &pVideoViData->sPortDef[i], sizeof(COMP_PARAM_PORTDEFINITIONTYPE)); } } if (i == VI_CHN_MAX_PORTS) { eError = FAILURE; } return eError; } ERRORTYPE DoVideoViSetPortDefinition(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_PARAM_PORTDEFINITIONTYPE *pPortDef) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; int i; for(i = 0; i < VI_CHN_MAX_PORTS; i++) { if (pPortDef->nPortIndex == pVideoViData->sPortDef[i].nPortIndex) { memcpy(&pVideoViData->sPortDef[i], pPortDef, sizeof(COMP_PARAM_PORTDEFINITIONTYPE)); } } if (i == VI_CHN_MAX_PORTS) { eError = FAILURE; } return eError; } ERRORTYPE DoVideoViGetCompBufferSupplier(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; int i; for(i=0; isPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) { memcpy(pPortBufSupplier, &pVideoViData->sPortBufSupplier[i], sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE)); break; } } if(i == VI_CHN_MAX_PORTS) { eError = FAILURE; } return eError; } ERRORTYPE DoVideoViSetCompBufferSupplier(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; int i; for(i=0; isPortBufSupplier[i].nPortIndex == pPortBufSupplier->nPortIndex) { memcpy(&pVideoViData->sPortBufSupplier[i], pPortBufSupplier, sizeof(COMP_PARAM_BUFFERSUPPLIERTYPE)); break; } } if(i == VI_CHN_MAX_PORTS) { eError = FAILURE; } return eError; } ERRORTYPE DoVideoViGetMPPChannelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT MPP_CHN_S *pChn) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); copy_MPP_CHN_S(pChn, &pVideoViData->mMppChnInfo); return SUCCESS; } ERRORTYPE DoVideoViSetMPPChannelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN MPP_CHN_S *pChn) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); copy_MPP_CHN_S(&pVideoViData->mMppChnInfo, pChn); return SUCCESS; } ERRORTYPE DoVideoViGetTunnelInfo(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_INOUT COMP_INTERNAL_TUNNELINFOTYPE *pTunnelInfo) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); ERRORTYPE eError = ERR_VI_UNEXIST; int i; for(i=0; isPortBufSupplier[i].nPortIndex == pTunnelInfo->nPortIndex) { memcpy(pTunnelInfo, &pVideoViData->sPortTunnelInfo[i], sizeof(COMP_INTERNAL_TUNNELINFOTYPE)); break; } } if(i == VI_CHN_MAX_PORTS) { eError = FAILURE; } return eError; } ERRORTYPE DoVideoViGetData(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT VI_Params *pstParams, PARAM_IN int nMilliSec) { ERRORTYPE eError = SUCCESS; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (COMP_StateIdle != pVideoViData->state && COMP_StateExecuting != pVideoViData->state) { alogw("call getStream in wrong state[0x%x]", pVideoViData->state); return ERR_VI_NOT_PERM; } int ret; /* not support get data in Tunnel mode for app */ if (TRUE == pVideoViData->mOutputPortTunnelFlag) { return ERR_VI_NOT_PERM; } /* for online, does not support get/release vipp data by user. */ if (pVideoViData->mViAttr.mOnlineEnable) { return ERR_VI_NOT_PERM; } VIDEO_FRAME_INFO_S *pstFrameInfo = pstParams->pstFrameInfo; VIDEO_FRAME_INFO_S *tmp = NULL; _TryToGetFrame: tmp = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if (NULL != tmp) goto GetFrmSuccess; if (0 == nMilliSec) return FAILURE; else if (nMilliSec < 0) { pVideoViData->mWaitingCapDataFlag = TRUE; tmp = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if (tmp != NULL) { pVideoViData->mWaitingCapDataFlag = FALSE; goto GetFrmSuccess; } else { cdx_sem_down(&pVideoViData->mSemWaitInputFrame); pVideoViData->mWaitingCapDataFlag = FALSE; goto _TryToGetFrame; } } else { pVideoViData->mWaitingCapDataFlag = TRUE; tmp = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if (tmp != NULL) { pVideoViData->mWaitingCapDataFlag = FALSE; goto GetFrmSuccess; } else { ret = cdx_sem_down_timedwait(&pVideoViData->mSemWaitInputFrame, nMilliSec); if(ETIMEDOUT == ret) { alogv("wait input frame timeout[%d]ms, ret[%d]", nMilliSec, ret); pVideoViData->mWaitingCapDataFlag = FALSE; return FAILURE; } else if(0 == ret) { pVideoViData->mWaitingCapDataFlag = FALSE; goto _TryToGetFrame; } else { aloge("fatal error! pthread cond wait timeout ret[%d]", ret); pVideoViData->mWaitingCapDataFlag = FALSE; return FAILURE; } } } GetFrmSuccess: memcpy(&pstFrameInfo->VFrame, &tmp->VFrame, sizeof(VIDEO_FRAME_INFO_S)); pstFrameInfo->mId = tmp->mId; //pstFrameInfo->VFrame.mOffsetTop = 0; //pstFrameInfo->VFrame.mOffsetBottom = pstFrameInfo->VFrame.mHeight; //pstFrameInfo->VFrame.mOffsetLeft = 0; //pstFrameInfo->VFrame.mOffsetRight = pstFrameInfo->VFrame.mWidth; alogv("DoVideoViGetData addr = %p.\r\n", pstFrameInfo->VFrame.mpVirAddr[0]); if(pVideoViData->mbStoreFrame) { char strPixFmt[16]; if(MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "nv21"); }else if(MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420 == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "nv12"); }else if(MM_PIXEL_FORMAT_YUV_AW_AFBC == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "afbc"); }else if(MM_PIXEL_FORMAT_YUV_AW_LBC_2_0X == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc20x"); }else if(MM_PIXEL_FORMAT_YUV_AW_LBC_2_5X == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc25x"); }else if(MM_PIXEL_FORMAT_YUV_AW_LBC_1_5X == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc15x"); }else if(MM_PIXEL_FORMAT_YUV_AW_LBC_1_0X == pstFrameInfo->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc10x"); } else { strcpy(strPixFmt, "unknown"); } int nPos = strlen(pVideoViData->mDbgStoreFrameFilePath); snprintf(pVideoViData->mDbgStoreFrameFilePath+nPos, VI_MAXPATHSIZE-nPos, "/vipp[%d]virChn[%d]pic[%d].%s", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, pVideoViData->mStoreFrameCount++, strPixFmt); FILE *dbgFp = fopen(pVideoViData->mDbgStoreFrameFilePath, "wb"); VideoFrameBufferSizeInfo FrameSizeInfo; getVideoFrameBufferSizeInfo(tmp, &FrameSizeInfo); int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize}; for(int i=0; i<3; i++) { if(tmp->VFrame.mpVirAddr[i] != NULL) { fwrite(tmp->VFrame.mpVirAddr[i], 1, yuvSize[i], dbgFp); alogd("virAddr[%d]=[%p], length=[%d]", i, tmp->VFrame.mpVirAddr[i], yuvSize[i]); } } fclose(dbgFp); pVideoViData->mbStoreFrame = FALSE; alogd("store VI frame in file[%s], non-tunnel mode", pVideoViData->mDbgStoreFrameFilePath); } return SUCCESS; } ERRORTYPE DoVideoViReleaseData(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN VI_Params *pstParams) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (COMP_StateIdle != pVideoViData->state && COMP_StateExecuting != pVideoViData->state) { alogw("call releaseStream in wrong state[0x%x], but still release it", pVideoViData->state); //return ERR_VI_NOT_PERM; } if (TRUE == pVideoViData->mOutputPortTunnelFlag) { /* Tunnel mode */ return ERR_VI_NOT_PERM; } /* for online, does not support get/release vipp data by user. */ if (pVideoViData->mViAttr.mOnlineEnable) { return ERR_VI_NOT_PERM; } int vipp_id = pstParams->mDev; VIDEO_FRAME_INFO_S *pstFrameInfo = pstParams->pstFrameInfo; videoInputHw_RefsReduceAndRleaseData(vipp_id, pstFrameInfo); VideoBufMgrReleaseFrame(pVideoViData->mpCapMgr, pstFrameInfo); alogv("DoVideoViReleaseData addr = %p.\r\n", pstFrameInfo->VFrame.mpVirAddr[0]); return SUCCESS; } static ERRORTYPE DoVideoViReturnAllValidFrames(PARAM_IN VIDEOVIDATATYPE *pVideoViData) { int nFrameNum = 0; VIDEO_FRAME_INFO_S *pFrame; while(1) { pFrame = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if(pFrame) { videoInputHw_RefsReduceAndRleaseData(pVideoViData->mMppChnInfo.mDevId, pFrame); VideoBufMgrReleaseFrame(pVideoViData->mpCapMgr, pFrame); nFrameNum++; } else { break; } } if(nFrameNum > 0) { alogv("release [%d]validFrames", nFrameNum); } int cnt = 0; struct list_head *pList; list_for_each(pList, &pVideoViData->mpCapMgr->mUsingFrmList) { cnt++; } if(cnt > 0) { alogw("Be careful! virchn[%d-%d] remain [%d] usingFrames after return all valid frames", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, cnt); } return SUCCESS; } /** * pDirPath: /mnt/extsd/VIDebug, */ ERRORTYPE VideoViStoreFrame(PARAM_IN COMP_HANDLETYPE hComponent, const char* pDirPath) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoViData->mOutputPortTunnelFlag) { alogw("in non-tunnel mode, you should store frame by your self, we don't do it\n"); return FAILURE; } message_t msg; InitMessage(&msg); msg.command = VViComp_StoreFrame; msg.mpData = (void*)pDirPath; msg.mDataSize = strlen(pDirPath)+1; putMessageWithData(&pVideoViData->cmd_queue, &msg); return SUCCESS; } /** * pstViShutter: see mm_common_vi.h -> awVI_SHUTTIME_CFG_S */ ERRORTYPE VideoViSetLongExpMode(PARAM_IN COMP_HANDLETYPE hComponent, VI_SHUTTIME_CFG_S *pstViShutter) { ERRORTYPE eErr = SUCCESS; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoViData->mLongExpLock); switch (pstViShutter->eShutterMode) { case VI_SHUTTIME_MODE_AUTO: break; case VI_SHUTTIME_MODE_PREVIEW: { aloge("not support this value until now, eShutterMode[%d]", pstViShutter->eShutterMode); eErr = ERR_VI_INVALID_PARA; goto exit; } break; case VI_SHUTTIME_MODE_NIGHT_VIEW: { if (pstViShutter->iTime > 0) { aloge("not support this value until now, iTime[%d]", pstViShutter->iTime); eErr = ERR_VI_INVALID_PARA; goto exit; } } break; default: { aloge("not support this value until now, eShutterMode[%d]", pstViShutter->eShutterMode); eErr = ERR_VI_INVALID_PARA; goto exit; } break; } if (pVideoViData->mSetLongExpCnt >= 1) { aloge("the long exposure mode has been set, do not set it again before returns normal."); eErr = ERR_VI_INVALID_PARA; goto exit; } else if (pstViShutter->eShutterMode == VI_SHUTTIME_MODE_AUTO) { alogd("The shutter mode now is auto already, return."); eErr = SUCCESS; goto exit; } memcpy(&pVideoViData->mLongExp, pstViShutter, sizeof(VI_SHUTTIME_CFG_S));; pVideoViData->mSetLongExpCnt++; message_t msg; memset(&msg, 0, sizeof(msg)); if (pVideoViData->mLongExp.eShutterMode == VI_SHUTTIME_MODE_NIGHT_VIEW) { msg.command = VViComp_LongExpEvent; msg.para0 = E_VI_LONGEXP_SET; msg.para1 = COMP_IndexVendorViSetLongExp; put_message(&pVideoViData->cmd_queue, &msg); } if (pVideoViData->mLongExp.eResetMode == VI_SHUTTIME_RESET_AUTO_NOW) { msg.command = VViComp_LongExpEvent; msg.para0 = E_VI_LONGEXP_RESET; msg.para1 = FF_LONGEXP; put_message(&pVideoViData->cmd_queue, &msg); } exit: pthread_mutex_unlock(&pVideoViData->mLongExpLock); /* we should return all buffers in valid frame list. */ DoVideoViReturnAllValidFrames(pVideoViData); return eErr; } /** * pstViAttr: see mm_common_vi.h -> awVI_ATTR_S */ ERRORTYPE VideoViGetViDevAttr(PARAM_IN COMP_HANDLETYPE hComponent, VI_ATTR_S *pstViAttr) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); memcpy(pstViAttr, &pVideoViData->mViAttr, sizeof(VI_ATTR_S)); return SUCCESS; } /** * pstViAttr: see mm_common_vi.h -> awVI_ATTR_S */ ERRORTYPE VideoViSetViDevAttr(PARAM_IN COMP_HANDLETYPE hComponent, VI_ATTR_S *pstViAttr) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); memcpy(&pVideoViData->mViAttr, pstViAttr, sizeof(VI_ATTR_S)); //aloge("fps %d nbufs %d", pVideoViData->mViAttr.fps, pVideoViData->mViAttr.nbufs); return SUCCESS; } ERRORTYPE VideoViGetViChnAttr(PARAM_IN COMP_HANDLETYPE hComponent, ViVirChnAttrS *pViVirChnAttr) { ERRORTYPE ret = SUCCESS; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoViData->mLock); if(pViVirChnAttr) { memcpy(pViVirChnAttr, &pVideoViData->mViVirChnAttr, sizeof(ViVirChnAttrS)); } else { ret = ERR_VI_INVALID_NULL_PTR; } pthread_mutex_unlock(&pVideoViData->mLock); return ret; } ERRORTYPE VideoViSetViChnAttr(PARAM_IN COMP_HANDLETYPE hComponent, ViVirChnAttrS *pViVirChnAttr) { VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); pthread_mutex_lock(&pVideoViData->mLock); if(pViVirChnAttr != NULL) { memcpy(&pVideoViData->mViVirChnAttr, pViVirChnAttr, sizeof(ViVirChnAttrS)); } pthread_mutex_unlock(&pVideoViData->mLock); return SUCCESS; } ERRORTYPE VideoViSendCommand(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_COMMANDTYPE Cmd, PARAM_IN unsigned int nParam1, PARAM_IN void *pCmdData) { VIDEOVIDATATYPE *pVideoViData; CompInternalMsgType eCmd; ERRORTYPE eError = SUCCESS; message_t msg; alogv("VideoViSendCommand: %d", Cmd); pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoViData) { eError = ERR_VI_INVALID_PARA; goto COMP_CONF_CMD_FAIL; } if (pVideoViData->state == COMP_StateInvalid) { eError = ERR_VI_SYS_NOTREADY; goto COMP_CONF_CMD_FAIL; } switch (Cmd) { case COMP_CommandStateSet: eCmd = SetState; break; case COMP_CommandFlush: eCmd = Flush; break; default: alogw("impossible comp_command[0x%x]", Cmd); eCmd = -1; break; } msg.command = eCmd; msg.para0 = nParam1; put_message(&pVideoViData->cmd_queue, &msg); COMP_CONF_CMD_FAIL: return eError; } ERRORTYPE VideoViGetState(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_OUT COMP_STATETYPE *pState) { ERRORTYPE eError = SUCCESS; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); *pState = pVideoViData->state; return eError; } ERRORTYPE VideoViSetCallbacks(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_CALLBACKTYPE *pCallbacks, PARAM_IN void *pAppData) { VIDEOVIDATATYPE *pVideoViData; ERRORTYPE eError = SUCCESS; pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if (!pVideoViData || !pCallbacks || !pAppData) { eError = ERR_VI_INVALID_PARA; goto COMP_CONF_CMD_FAIL; } pVideoViData->pCallbacks = pCallbacks; pVideoViData->pAppData = pAppData; COMP_CONF_CMD_FAIL: return eError; } ERRORTYPE VideoViGetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex, PARAM_IN void *pComponentConfigStructure) { // VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; switch (nIndex) { case COMP_IndexParamPortDefinition: { eError = DoVideoViGetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure); } break; case COMP_IndexParamCompBufferSupplier: { eError = DoVideoViGetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure); } break; case COMP_IndexVendorMPPChannelInfo: { eError = DoVideoViGetMPPChannelInfo(hComponent, (MPP_CHN_S *)pComponentConfigStructure); } break; case COMP_IndexVendorViGetFrame: { VI_Params *pData = (VI_Params *)pComponentConfigStructure; eError = DoVideoViGetData(hComponent, pData, pData->s32MilliSec); } break; case COMP_IndexVendorTunnelInfo: { eError = DoVideoViGetTunnelInfo(hComponent, (COMP_INTERNAL_TUNNELINFOTYPE *)pComponentConfigStructure); } break; case COMP_IndexVendorViDevAttr: { eError = VideoViGetViDevAttr(hComponent, (VI_ATTR_S *)pComponentConfigStructure); } break; case COMP_IndexVendorViChnAttr: { eError = VideoViGetViChnAttr(hComponent, (ViVirChnAttrS*)pComponentConfigStructure); break; } default: { aloge("fatal error! unknown getConfig Index[0x%x]", nIndex); eError = ERR_VI_NOT_SUPPORT; } break; } return eError; } ERRORTYPE VideoViSetConfig(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_INDEXTYPE nIndex, PARAM_IN void *pComponentConfigStructure) { // VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); ERRORTYPE eError = SUCCESS; switch (nIndex) { case COMP_IndexParamPortDefinition: { eError = DoVideoViSetPortDefinition(hComponent, (COMP_PARAM_PORTDEFINITIONTYPE *)pComponentConfigStructure); } break; case COMP_IndexParamCompBufferSupplier: { eError = DoVideoViSetCompBufferSupplier(hComponent, (COMP_PARAM_BUFFERSUPPLIERTYPE *)pComponentConfigStructure); } break; case COMP_IndexVendorMPPChannelInfo: { eError = DoVideoViSetMPPChannelInfo(hComponent, (MPP_CHN_S *)pComponentConfigStructure); } break; case COMP_IndexVendorViReleaseFrame: { eError = DoVideoViReleaseData(hComponent, (VI_Params *)pComponentConfigStructure); } break; case COMP_IndexVendorViStoreFrame: { eError = VideoViStoreFrame(hComponent, (const char*)pComponentConfigStructure); } break; case COMP_IndexVendorViSetLongExp: { eError = VideoViSetLongExpMode(hComponent, (VI_SHUTTIME_CFG_S *)pComponentConfigStructure); } break; case COMP_IndexVendorViDevAttr: { eError = VideoViSetViDevAttr(hComponent, (VI_ATTR_S *)pComponentConfigStructure); } break; case COMP_IndexVendorViChnAttr: { eError = VideoViSetViChnAttr(hComponent, (ViVirChnAttrS*)pComponentConfigStructure); break; } default: { aloge("(f:%s, l:%d) unknown Index[0x%x]", __FUNCTION__, __LINE__, nIndex); eError = ERR_VI_INVALID_PARA; } break; } return eError; } ERRORTYPE VideoViComponentTunnelRequest(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; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); COMP_PARAM_PORTDEFINITIONTYPE *pPortDef; COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo; COMP_PARAM_BUFFERSUPPLIERTYPE *pPortBufSupplier; int i; if (pVideoViData->state == COMP_StateExecuting) { alogw("Be careful! tunnel request may be some danger in StateExecuting"); } else if (pVideoViData->state != COMP_StateIdle) { aloge("fatal error! tunnel request can't be in state[0x%x]",pVideoViData->state); eError = ERR_VI_INCORRECT_STATE_OPERATION; goto COMP_CMD_FAIL; } for (i = 0; i < VI_CHN_MAX_PORTS; ++i) { if (pVideoViData->sPortDef[i].nPortIndex == nPort) { pPortDef = &pVideoViData->sPortDef[i]; break; } } if (i == VI_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_AI_ILLEGAL_PARAM; goto COMP_CMD_FAIL; } for (i = 0; i < VI_CHN_MAX_PORTS; ++i) { if (pVideoViData->sPortTunnelInfo[i].nPortIndex == nPort) { pPortTunnelInfo = &pVideoViData->sPortTunnelInfo[i]; break; } } if (i == VI_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_AI_ILLEGAL_PARAM; goto COMP_CMD_FAIL; } for (i = 0; i < VI_CHN_MAX_PORTS; ++i) { if (pVideoViData->sPortBufSupplier[i].nPortIndex == nPort) { pPortBufSupplier = &pVideoViData->sPortBufSupplier[i]; break; } } if (i == VI_CHN_MAX_PORTS) { aloge("fatal error! portIndex[%d] wrong!", nPort); eError = ERR_AI_ILLEGAL_PARAM; goto COMP_CMD_FAIL; } pPortTunnelInfo->nPortIndex = nPort; pPortTunnelInfo->hTunnel = hTunneledComp; pPortTunnelInfo->nTunnelPortIndex = nTunneledPort; pPortTunnelInfo->eTunnelType = (pPortDef->eDomain == COMP_PortDomainOther) ? TUNNEL_TYPE_CLOCK : TUNNEL_TYPE_COMMON; if(NULL==hTunneledComp && 0==nTunneledPort && NULL==pTunnelSetup) { alogd("omx_core cancel setup tunnel on port[%d]", nPort); eError = SUCCESS; if(pPortDef->eDir == COMP_DirOutput) { pVideoViData->mOutputPortTunnelFlag = FALSE; } else { pVideoViData->mInputPortTunnelFlag = FALSE; } goto COMP_CMD_FAIL; } if(pPortDef->eDir == COMP_DirOutput) { if (pVideoViData->mOutputPortTunnelFlag) { aloge("VirVi_Comp outport already bind, why bind again?!"); eError = FAILURE; goto COMP_CMD_FAIL; } pTunnelSetup->nTunnelFlags = 0; pTunnelSetup->eSupplier = pPortBufSupplier->eBufferSupplier; pVideoViData->mOutputPortTunnelFlag = TRUE; } else { if (pVideoViData->mInputPortTunnelFlag) { aloge("VirVi_Comp inport already bind, why bind again?!"); eError = FAILURE; goto COMP_CMD_FAIL; } //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 out_port_def; out_port_def.nPortIndex = nTunneledPort; ((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamPortDefinition, &out_port_def); if(out_port_def.eDir != COMP_DirOutput) { aloge("fatal error! tunnel port index[%d] direction is not output!", nTunneledPort); eError = ERR_VI_INVALID_PARA; goto COMP_CMD_FAIL; } pPortDef->format = out_port_def.format; //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; ((MM_COMPONENTTYPE*)hTunneledComp)->GetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier); oSupplier.eBufferSupplier = pTunnelSetup->eSupplier; ((MM_COMPONENTTYPE*)hTunneledComp)->SetConfig(hTunneledComp, COMP_IndexParamCompBufferSupplier, &oSupplier); pVideoViData->mInputPortTunnelFlag = TRUE; } COMP_CMD_FAIL: return eError; } ERRORTYPE VideoViEmptyThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer) { ERRORTYPE eError = SUCCESS; ERRORTYPE ret; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); VIDEO_FRAME_INFO_S *pFrm = (VIDEO_FRAME_INFO_S *)pBuffer->pOutputPortPrivate; uint64_t FrmIntervalMs = (pFrm->VFrame.mpts-pVideoViData->mLastFrmPtsCache)/1000; unsigned int FrmCntInterval = pFrm->VFrame.mFramecnt-pVideoViData->mLastFrmCnt; int iGetLongExpFlag = 0; /* long exposure mode should be 1S and lager time interval, * if the time interval is less than 1S, it may be regarded as normal frame. */ if (0 != pVideoViData->mLastFrmPtsCache && (FrmIntervalMs>1000/pVideoViData->mViAttr.fps*FrmCntInterval+500)) { iGetLongExpFlag = 1; } pFrm->VFrame.mWhoSetFlag = (pVideoViData->mMppChnInfo.mModId<<16) | (pVideoViData->mMppChnInfo.mDevId<<8) | (pVideoViData->mMppChnInfo.mChnId); pVideoViData->mLastFrmPtsCache = pFrm->VFrame.mpts; pVideoViData->mLastFrmCnt = pFrm->VFrame.mFramecnt; pthread_mutex_lock(&pVideoViData->mStateLock); bool bDiscardFlag = false; if(COMP_StateExecuting == pVideoViData->state || COMP_StatePause == pVideoViData->state) { bDiscardFlag = false; } else if(COMP_StateIdle == pVideoViData->state) { BOOL bRecv = pVideoViData->mViVirChnAttr.mbRecvInIdleState; if(bRecv) { //bDiscardFlag = false; alogw("Be careful! Sorry, viChn[%d-%d] don't support to receive frame in idle state!", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); bDiscardFlag = true; } else { bDiscardFlag = true; } } else { bDiscardFlag = true; } if(bDiscardFlag) { //alogw("vipp[%d,%d] send frameId[%d,%d] in vi state[0x%x], discard!", pVideoViData->mMppChnInfo.mDevId, // pVideoViData->mMppChnInfo.mChnId, pFrm->mId, pFrm->VFrame.mFramecnt, pVideoViData->state); eError = FAILURE; goto err_state; } pthread_mutex_lock(&pVideoViData->mLongExpLock); if (pVideoViData->mLongExp.eShutterMode == VI_SHUTTIME_MODE_AUTO) { /* normal mode, but still should check if is long exposure frame */ if (pVideoViData->mSetLongExpCnt == 0) { /* do nothing */; } else if (pVideoViData->mLongExpFrameCnt == pFrm->VFrame.mFramecnt) { pVideoViData->mSetLongExpCnt = 0; } else { pthread_mutex_unlock(&pVideoViData->mLongExpLock); eError = FAILURE; aloge("FrmIntervalMs %llu, not a long exposure video frame", FrmIntervalMs); goto err_state; } } else if (pVideoViData->mLongExp.eShutterMode == VI_SHUTTIME_MODE_NIGHT_VIEW) { if (iGetLongExpFlag) { pVideoViData->mLongExpFrameCnt = pFrm->VFrame.mFramecnt + pVideoViData->mLongExpFrameDelay; /* if it is not reset manual, I resume to AUTO mode by myself,. * else, if pVideoViData->mSetLongExpCnt == 1; it says somebody set * VI_SHUTTIME_MODE_AUTO, so we should set to VI_SHUTTIME_MODE_AUTO */ pVideoViData->mLongExp.eShutterMode = VI_SHUTTIME_MODE_AUTO; if (pVideoViData->mLongExp.eResetMode == VI_SHUTTIME_RESET_AUTO_DELAY) { message_t msg; msg.command = VViComp_LongExpEvent; msg.para0 = E_VI_LONGEXP_RESET; msg.para1 = FF_LONGEXP; put_message(&pVideoViData->cmd_queue, &msg); } aloge("FrmIntervalMs %llu, mode %d, cnt %d", FrmIntervalMs, pVideoViData->mLongExp.eShutterMode, pVideoViData->mSetLongExpCnt); } if (pFrm->VFrame.mFramecnt >= pVideoViData->mLongExpFrameCnt) { pVideoViData->mSetLongExpCnt = 0; } else { pthread_mutex_unlock(&pVideoViData->mLongExpLock); eError = FAILURE; aloge("FrmIntervalMs %llu, not a long exposure video frame", FrmIntervalMs); aloge("Real long exposure frame count %d, this frame count %d", pVideoViData->mLongExpFrameCnt, pFrm->VFrame.mFramecnt); goto err_state; } } pthread_mutex_unlock(&pVideoViData->mLongExpLock); /* put data ptr to CapMgr_queue for tunnel or user mpi_get\release */ if (pBuffer->nInputPortIndex == pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].nPortIndex) { if(pVideoViData->mOutputPortTunnelFlag) { bDiscardFlag = false; if(pVideoViData->mViVirChnAttr.mCacheFrameNum > 0) { int nFrameNum = pVideoViData->mpCapMgr->GetValidUsingFrameNum(pVideoViData->mpCapMgr); if(nFrameNum >= pVideoViData->mViVirChnAttr.mCacheFrameNum) { //cache frame number is enough, discard current frame. bDiscardFlag = true; eError = FAILURE; } } if(!bDiscardFlag) { pthread_mutex_lock(&pVideoViData->mFrameLock); eError = VideoBufMgrPushFrame(pVideoViData->mpCapMgr, pFrm); if (eError != SUCCESS) { pthread_mutex_unlock(&pVideoViData->mFrameLock); aloge("fatal error! failed to push this frame, it will be droped"); eError = FAILURE; goto push_fail; } alogv("VideoViEmptyThisBuffer pushFrame process, %p.\r\n", pFrm->VFrame.mpVirAddr[0]); pthread_mutex_unlock(&pVideoViData->mFrameLock); /* Tunnel mode, send frame to next component */ //alogw("Tunnel virvi debug.\r\n"); COMP_INTERNAL_TUNNELINFOTYPE *pPortTunnelInfo = &pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_OUT]; MM_COMPONENTTYPE *pOutTunnelComp = (MM_COMPONENTTYPE*)pPortTunnelInfo->hTunnel; if (pOutTunnelComp != NULL) { COMP_BUFFERHEADERTYPE obh; pthread_mutex_lock(&pVideoViData->mFrameLock); VIDEO_FRAME_INFO_S *pFrm = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if (pFrm == NULL) { aloge("fatal error! no valid frame? check code!"); } pthread_mutex_unlock(&pVideoViData->mFrameLock); if(pVideoViData->mbStoreFrame) { char strPixFmt[16]; if(MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420 == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "nv21"); } else if(MM_PIXEL_FORMAT_YUV_SEMIPLANAR_420 == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "nv12"); } else if(MM_PIXEL_FORMAT_YUV_AW_AFBC == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "afbc"); } else if(MM_PIXEL_FORMAT_YUV_AW_LBC_2_0X == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc20x"); } else if(MM_PIXEL_FORMAT_YUV_AW_LBC_2_5X == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc25x"); } else if(MM_PIXEL_FORMAT_YUV_AW_LBC_1_5X == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc15x"); } else if(MM_PIXEL_FORMAT_YUV_AW_LBC_1_0X == pFrm->VFrame.mPixelFormat) { strcpy(strPixFmt, "lbc10x"); } else { strcpy(strPixFmt, "unknown"); } int nPos = strlen(pVideoViData->mDbgStoreFrameFilePath); snprintf(pVideoViData->mDbgStoreFrameFilePath+nPos, VI_MAXPATHSIZE-nPos, "/vipp[%d]virChn[%d]frmId[%d]pic[%d].%s", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, pFrm->mId, pVideoViData->mStoreFrameCount++, strPixFmt); FILE *dbgFp = fopen(pVideoViData->mDbgStoreFrameFilePath, "wb"); VideoFrameBufferSizeInfo FrameSizeInfo; getVideoFrameBufferSizeInfo(pFrm, &FrameSizeInfo); int yuvSize[3] = {FrameSizeInfo.mYSize, FrameSizeInfo.mUSize, FrameSizeInfo.mVSize}; for(int i=0; i<3; i++) { if(pFrm->VFrame.mpVirAddr[i] != NULL) { fwrite(pFrm->VFrame.mpVirAddr[i], 1, yuvSize[i], dbgFp); alogd("virAddr[%d]=[%p], length=[%d]", i, pFrm->VFrame.mpVirAddr[i], yuvSize[i]); } } fclose(dbgFp); pVideoViData->mbStoreFrame = FALSE; alogd("store VI frame in file[%s]", pVideoViData->mDbgStoreFrameFilePath); } obh.nOutputPortIndex = pPortTunnelInfo->nPortIndex; obh.nInputPortIndex = pPortTunnelInfo->nTunnelPortIndex; //obh.pOutputPortPrivate = pFrm; obh.pOutputPortPrivate = pFrm; ret = COMP_EmptyThisBuffer(pOutTunnelComp, &obh); if(SUCCESS != ret) { if(ERR_VENC_BUF_FULL == ret) { alogd("viChn[%d-%d] detect refuse because limited frame number, ret[0x%x].", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, ret); } else if(ERR_VENC_INCORRECT_STATE_OPERATION == ret) { alogd("viChn[%d-%d] detect refuse because state is incorrect, ret[0x%x].", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, ret); } else if(ERR_VENC_NOT_PERM == ret) { alogv("viChn[%d-%d] detect refuse because frame not satisfy condition, ret[0x%x].", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, ret); } else { alogw("viChn[%d-%d] OutTunnelComp EmptyThisBuffer failed[%x], return this frame", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId, ret); } //videoInputHw_RefsReduceAndRleaseData(pVideoViData->mMppChnInfo.mDevId, pFrm); VideoBufMgrReleaseFrame(pVideoViData->mpCapMgr, pFrm); eError = FAILURE; } } else { aloge("fatal error! viChn[%d-%d] why tunnel comp is NULL?", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); eError = FAILURE; } } } else { bDiscardFlag = false; BOOL bNeedSendDropFrameMsg = FALSE; if(pVideoViData->mViVirChnAttr.mCacheFrameNum > 0) { int nFrameNum = pVideoViData->mpCapMgr->GetValidUsingFrameNum(pVideoViData->mpCapMgr); if(nFrameNum >= pVideoViData->mViVirChnAttr.mCacheFrameNum) { if(0 == pVideoViData->mViVirChnAttr.mCachePolicy) { bDiscardFlag = true; bNeedSendDropFrameMsg = FALSE; //cache frame number is enough, discard current frame. eError = FAILURE; } else if(1 == pVideoViData->mViVirChnAttr.mCachePolicy) { bDiscardFlag = false; //cache frame number is enough, discard old frame. bNeedSendDropFrameMsg = TRUE; alogv("nFrameNum=%d, VViComp DropFrame", nFrameNum); } else { aloge("fatal error! Cache Policy %d is NOT supported!", pVideoViData->mViVirChnAttr.mCachePolicy); } } } if(!bDiscardFlag) { pthread_mutex_lock(&pVideoViData->mFrameLock); eError = VideoBufMgrPushFrame(pVideoViData->mpCapMgr, pFrm); if (eError != SUCCESS) { pthread_mutex_unlock(&pVideoViData->mFrameLock); aloge("failed to push this frame, it will be droped\n"); eError = FAILURE; goto push_fail; } alogv("VideoViEmptyThisBuffer pushFrame process, %p.\r\n", pFrm->VFrame.mpVirAddr[0]); if (pVideoViData->mWaitingCapDataFlag) { cdx_sem_up(&pVideoViData->mSemWaitInputFrame); pVideoViData->mWaitingCapDataFlag = FALSE; } pthread_mutex_unlock(&pVideoViData->mFrameLock); } if(bNeedSendDropFrameMsg) { message_t msg; msg.command = VViComp_DropFrame; put_message(&pVideoViData->cmd_queue, &msg); } } } // else if (pBuffer->nOutputPortIndex == pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].nPortIndex) // { // } else { aloge("fatal error! inputPortIndex[%d] match nothing!", pBuffer->nOutputPortIndex); } push_fail: err_state: pthread_mutex_unlock(&pVideoViData->mStateLock); return eError; } ERRORTYPE VideoViFillThisBuffer(PARAM_IN COMP_HANDLETYPE hComponent, PARAM_IN COMP_BUFFERHEADERTYPE *pBuffer) { VIDEOVIDATATYPE *pVideoViData; ERRORTYPE eError = SUCCESS; int ret; pVideoViData = (VIDEOVIDATATYPE *) (((MM_COMPONENTTYPE*) hComponent)->pComponentPrivate); if (COMP_StateIdle != pVideoViData->state && COMP_StateExecuting != pVideoViData->state) { alogw("call fillThisBuffer in wrong state[0x%x], but still release it", pVideoViData->state); } if (pBuffer->nOutputPortIndex == pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].nPortIndex) { VIDEO_FRAME_INFO_S *pFrm = pBuffer->pOutputPortPrivate; videoInputHw_RefsReduceAndRleaseData(pVideoViData->mMppChnInfo.mDevId, pFrm); VideoBufMgrReleaseFrame(pVideoViData->mpCapMgr, pFrm); } else { aloge("fatal error! outputPortIndex[%d]!=[%d]", pBuffer->nOutputPortIndex, pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].nPortIndex); } return 0; } ERRORTYPE VideoViComponentDeInit(PARAM_IN COMP_HANDLETYPE hComponent) { VIDEOVIDATATYPE *pVideoViData = NULL; message_t msg; struct list_head *pList; ERRORTYPE eError = SUCCESS; CompInternalMsgType eCmd = Stop; int cnt = 0; pVideoViData = (VIDEOVIDATATYPE *)(((MM_COMPONENTTYPE *)hComponent)->pComponentPrivate); if(NULL == pVideoViData) { aloge("pVideoViData is NULL!!!\n"); return FAILURE; } msg.command = eCmd; put_message(&pVideoViData->cmd_queue, &msg); if(NULL != pVideoViData) { pthread_join(pVideoViData->thread_id, (void *)&eError); } message_destroy(&pVideoViData->cmd_queue); pthread_mutex_destroy(&pVideoViData->mLongExpLock); pthread_mutex_destroy(&pVideoViData->mStateLock); pthread_mutex_destroy(&pVideoViData->mFrameLock); pthread_mutex_destroy(&pVideoViData->mLock); if(NULL != pVideoViData) { VideoBufMgrDestroy(pVideoViData->mpCapMgr); } cdx_sem_deinit(&pVideoViData->mSemWaitInputFrame); if(NULL != pVideoViData) { pVideoViData->mpCapMgr = NULL; } if (pVideoViData) { free(pVideoViData); pVideoViData = NULL; } alogv("VideoVirvi component exited!"); return eError; } ERRORTYPE VideoViComponentInit(PARAM_IN COMP_HANDLETYPE hComponent) { ERRORTYPE eError = SUCCESS; int i = 0; MM_COMPONENTTYPE *pComp = (MM_COMPONENTTYPE *)hComponent; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)malloc(sizeof(VIDEOVIDATATYPE)); if (NULL == pVideoViData) { aloge("fatal error, malloc pVideoViData fail!"); return ERR_VI_NOMEM; } memset(pVideoViData, 0x0, sizeof(VIDEOVIDATATYPE)); pComp->pComponentPrivate = (void *)pVideoViData; pVideoViData->state = COMP_StateLoaded; pthread_mutex_init(&pVideoViData->mStateLock, NULL); pthread_mutex_init(&pVideoViData->mFrameLock, NULL); pthread_mutex_init(&pVideoViData->mLock, NULL); pthread_mutex_init(&pVideoViData->mLongExpLock, NULL); pVideoViData->mLongExpFrameDelay = 1; pVideoViData->hSelf = hComponent; cdx_sem_init(&pVideoViData->mSemWaitInputFrame, 0); pVideoViData->mpCapMgr = VideoBufMgrCreate(VI_FIFO_LEVEL, 0); if (pVideoViData->mpCapMgr == NULL) { aloge("videoInputBufMgrCreate error!"); return FAILURE; } // Fill in function pointers pComp->SetCallbacks = VideoViSetCallbacks; pComp->SendCommand = VideoViSendCommand; pComp->GetConfig = VideoViGetConfig; pComp->SetConfig = VideoViSetConfig; pComp->GetState = VideoViGetState; pComp->ComponentTunnelRequest = VideoViComponentTunnelRequest; pComp->ComponentDeInit = VideoViComponentDeInit; pComp->EmptyThisBuffer = VideoViEmptyThisBuffer; pComp->FillThisBuffer = VideoViFillThisBuffer; // Initialize component data structures to default values pVideoViData->sPortParam.nPorts = 0; pVideoViData->sPortParam.nStartPortNumber = 0x0; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].bEnabled = TRUE; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].eDomain = COMP_PortDomainVideo; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].eDir = COMP_DirInput; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].format.video.cMIMEType = "YVU420"; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].format.video.nFrameWidth = 176; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].format.video.nFrameHeight = 144; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].format.video.eCompressionFormat = PT_BUTT; // YCbCr420; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_CAP_IN].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_CAP_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_CAP_IN].eBufferSupplier = COMP_BufferSupplyOutput; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_CAP_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_CAP_IN].eTunnelType = TUNNEL_TYPE_COMMON; pVideoViData->sPortParam.nPorts++; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].bEnabled = TRUE; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].eDomain = COMP_PortDomainVideo; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].eDir = COMP_DirInput; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].format.video.cMIMEType = "YVU420"; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].format.video.nFrameWidth = 176; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].format.video.nFrameHeight = 144; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].format.video.eCompressionFormat = PT_BUTT; // YCbCr420; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_FILE_IN].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_FILE_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_FILE_IN].eBufferSupplier = COMP_BufferSupplyOutput; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_FILE_IN].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_FILE_IN].eTunnelType = TUNNEL_TYPE_COMMON; pVideoViData->sPortParam.nPorts++; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].bEnabled = TRUE; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].eDomain = COMP_PortDomainVideo; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].eDir = COMP_DirOutput; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].format.video.cMIMEType = "YVU420"; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].format.video.nFrameWidth = 176; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].format.video.nFrameHeight = 144; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].format.video.eCompressionFormat = PT_BUTT; // YCbCr420; pVideoViData->sPortDef[VI_CHN_PORT_INDEX_OUT].format.video.eColorFormat = MM_PIXEL_FORMAT_YVU_SEMIPLANAR_420; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_OUT].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortBufSupplier[VI_CHN_PORT_INDEX_OUT].eBufferSupplier = COMP_BufferSupplyOutput; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_OUT].nPortIndex = pVideoViData->sPortParam.nPorts; pVideoViData->sPortTunnelInfo[VI_CHN_PORT_INDEX_OUT].eTunnelType = TUNNEL_TYPE_COMMON; pVideoViData->sPortParam.nPorts++; if (message_create(&pVideoViData->cmd_queue) < 0) { aloge("message error!"); eError = ERR_VI_NOMEM; goto EXIT; } // Create the component thread if (pthread_create(&pVideoViData->thread_id, NULL, Vi_ComponentThread, pVideoViData) /*|| !pVideoViData->thread_id*/) { aloge("(f:%s, l:%d) create Vi_Component Thread fail!\r\n", __FUNCTION__, __LINE__); eError = ERR_VI_NOMEM; goto EXIT; } alogv("VideoVirvi component Init! thread_id[0x%x]", pVideoViData->thread_id); EXIT: return eError; } static void *Vi_ComponentThread(void *pThreadData) { unsigned int cmddata; CompInternalMsgType cmd; VIDEOVIDATATYPE *pVideoViData = (VIDEOVIDATATYPE *)pThreadData; message_t cmd_msg; alogv("VideoVi ComponentThread start run..."); sprintf(pVideoViData->mThreadName, "VIChn[%d-%d]", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); prctl(PR_SET_NAME, (unsigned long)pVideoViData->mThreadName, 0, 0, 0); while (1) { PROCESS_MESSAGE: if (get_message(&pVideoViData->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(&pVideoViData->mStateLock); if (pVideoViData->state == (COMP_STATETYPE)(cmddata)) { pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_SAMESTATE, 0, NULL); } else { switch ((COMP_STATETYPE)(cmddata)) { case COMP_StateInvalid: { pVideoViData->state = COMP_StateInvalid; // CompSendEvent(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INVALIDSTATE, 0); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INVALIDSTATE, 0, NULL); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); break; } case COMP_StateLoaded: { if (pVideoViData->state != COMP_StateIdle) { pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } pVideoViData->mWaitAllFrameReleaseFlag = 1; alogv("viChn[%d-%d]:begin to wait using frame return", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); VideoBufMgrWaitUsingEmpty(pVideoViData->mpCapMgr); alogv("viChn[%d-%d] wait using frame return done", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); pVideoViData->mWaitAllFrameReleaseFlag = 0; //return all valid frames to videoInput DoVideoViReturnAllValidFrames(pVideoViData); pVideoViData->state = COMP_StateLoaded; alogv("viChn[%d-%d] Set Virvi OMX_StateLoaded OK", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); break; } case COMP_StateIdle: { if (pVideoViData->state == COMP_StateLoaded) { alogv("video VI: loaded->idle ..."); pVideoViData->state = COMP_StateIdle; // callback sem++ pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); } else if (pVideoViData->state == COMP_StatePause || pVideoViData->state == COMP_StateExecuting) { alogv("video vi: pause/executing[0x%x]->idle ...", pVideoViData->state); //release all frames to video input. if(!VideoBufMgrUsingEmpty(pVideoViData->mpCapMgr)) { // aloge("fatal error! using frame is not empty! check code!"); alogw("Be careful! virChn[%d-%d] using frame is not empty!", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); } //return all valid frames to videoInput DoVideoViReturnAllValidFrames(pVideoViData); pVideoViData->state = COMP_StateIdle; alogv("Set Virvi COMP_StateIdle OK"); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); } else { aloge("fatal error! current state[0x%x] can't turn to idle!", pVideoViData->state); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } break; } case COMP_StateExecuting: { // Transition can only happen from pause or idle state if (pVideoViData->state == COMP_StateIdle || pVideoViData->state == COMP_StatePause) { pVideoViData->state = COMP_StateExecuting; alogv("Set Virvi COMP_StateExecuting OK"); pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); } else { pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } break; } case COMP_StatePause: { // Transition can only happen from idle or executing state if (pVideoViData->state == COMP_StateIdle || pVideoViData->state == COMP_StateExecuting) { pVideoViData->state = COMP_StatePause; pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventCmdComplete, COMP_CommandStateSet, pVideoViData->state, NULL); } else { pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventError, ERR_VI_INCORRECT_STATE_TRANSITION, 0, NULL); } break; } default: { break; } } } pthread_mutex_unlock(&pVideoViData->mStateLock); } else if (cmd == Flush) { alogv("Receive command Flush."); } else if (cmd == Stop) { goto EXIT; /* Kill thread */ } else if (cmd == VViComp_InputFrameAvailable) { alogv("(f:%s, l:%d) frame input", __FUNCTION__, __LINE__); } else if (cmd == VViComp_DropFrame) { alogv("frame drop"); } else if (cmd == VViComp_LongExpEvent) { if (E_VI_LONGEXP_SET == cmd_msg.para0) { pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventBufferFlag, cmd_msg.para1, pVideoViData->mMppChnInfo.mDevId, NULL); } else if (E_VI_LONGEXP_RESET == cmd_msg.para0) { VI_SHUTTIME_CFG_S mShutter; mShutter.eShutterMode = VI_SHUTTIME_MODE_AUTO; pVideoViData->pCallbacks->EventHandler(pVideoViData->hSelf, pVideoViData->pAppData, COMP_EventBufferFlag, cmd_msg.para1, pVideoViData->mMppChnInfo.mDevId, (void *)&mShutter); } } else if (cmd == VViComp_StoreFrame) { if(FALSE == pVideoViData->mbStoreFrame) { pVideoViData->mbStoreFrame = TRUE; } else { alogw("Be careful! storeFrame is already true! maybe process slow."); } snprintf(pVideoViData->mDbgStoreFrameFilePath, sizeof(pVideoViData->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; } if (pVideoViData->state == COMP_StateExecuting) { /* For online, csi&ve driver transfer data directly, and virvi channel does not need to process data. */ if (0 != pVideoViData->mViAttr.mOnlineEnable) { TMessage_WaitQueueNotEmpty(&pVideoViData->cmd_queue, 0); goto PROCESS_MESSAGE; } /* For offline. */ if (TRUE == pVideoViData->mOutputPortTunnelFlag) { int msgNum = TMessage_WaitQueueNotEmpty(&pVideoViData->cmd_queue, 2000); if(0 == msgNum) { alogv("viChn[%d-%d] has no message", pVideoViData->mMppChnInfo.mDevId, pVideoViData->mMppChnInfo.mChnId); } goto PROCESS_MESSAGE; } else { /* non-Tunnel */ if(pVideoViData->mViVirChnAttr.mCacheFrameNum > 0) { if (1 == pVideoViData->mViVirChnAttr.mCachePolicy) { int nFrameNum = 0; do { nFrameNum = pVideoViData->mpCapMgr->GetValidUsingFrameNum(pVideoViData->mpCapMgr); alogv("nFrameNum=%d", nFrameNum); if(nFrameNum <= pVideoViData->mViVirChnAttr.mCacheFrameNum) { break; } VIDEO_FRAME_INFO_S *pOldFrm = VideoBufMgrGetValidFrame(pVideoViData->mpCapMgr); if (pOldFrm) { videoInputHw_RefsReduceAndRleaseData(pVideoViData->mMppChnInfo.mDevId, pOldFrm); VideoBufMgrReleaseFrame(pVideoViData->mpCapMgr, pOldFrm); } else { alogw("Be careful. too many frames[%d] out, more than [%d]cacheFrames", nFrameNum, pVideoViData->mViVirChnAttr.mCacheFrameNum); break; } } while(1); } } TMessage_WaitQueueNotEmpty(&pVideoViData->cmd_queue, 1000); } } else { alogv("VI ComponentThread not OMX_StateExecuting\n"); TMessage_WaitQueueNotEmpty(&pVideoViData->cmd_queue, 0); } } EXIT: alogv("VideoVirvi ComponentThread stopped"); return (void *)SUCCESS; }