sdk-hwV1.3/external/eyesee-mpp/middleware/sun8iw21/media/component/VideoVirVi_Component.c

1536 lines
65 KiB
C
Executable File

/******************************************************************************
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 <utils/plat_log.h>
//ref platform headers
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "plat_defines.h"
#include "plat_errno.h"
#include "plat_math.h"
#include "plat_type.h"
#include "cdx_list.h"
#include "SystemBase.h"
#include <VIDEO_FRAME_INFO_S.h>
#include "mm_comm_vi.h"
#include "mm_comm_video.h"
#include <mm_comm_venc.h>
#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 <sys/prctl.h>
#include <pthread.h>
#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; i<VI_CHN_MAX_PORTS; i++) {
if(pVideoViData->sPortBufSupplier[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; i<VI_CHN_MAX_PORTS; i++) {
if(pVideoViData->sPortBufSupplier[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; i<VI_CHN_MAX_PORTS; i++) {
if(pVideoViData->sPortBufSupplier[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;
}