每个link都有管理着自己的队列,相当于一个内存池,一个输入队列,一个输出队列,当一个link处理完后,将数据放在自己的输出队列后,通过发送通知的方式告诉下一个link取数据,这个地方涉及到多核通信;
Link Output Queue – is the queue which is used by another link (via the inter link API) to exchange frames with that link
下面是IPCBitsOutLink:
Link数据结构:
typedef struct IpcBitsOutLink_Obj {
UInt32 tskId; /**< IpcBitsOutLink instance linkID */
OSA_TskHndl tsk; /**< IpcBitsInLink task handle */
IpcBitsOutLinkHLOS_CreateParams createArgs;
/**< Application passed create Args */
ListMP_Handle listMPOutHndl; /**< IPC SystemIpcBits_ListElem full queue */
ListMP_Handle listMPInHndl; /**< IPC SystemIpcBits_ListElem empty queue */
GateMP_Handle gateMPInHndl; /**< IPC Gate for listMPOutHndl */
GateMP_Handle gateMPOutHndl; /**< IPC Gate for listMPInHndl */
SystemIpcBits_ListElem *listElem[SYSTEM_IPC_BITS_MAX_LIST_ELEM];
/**< Array of listElems populated at creat time */
OSA_QueHndl listElemQue[IPC_BITS_OUT_MAX_NUM_ALLOC_POOLS];
/**< Queue holding free listElems */
Ptr bitBufPoolPtr[IPC_BITS_OUT_MAX_NUM_ALLOC_POOLS];
/**< Pool bit buffer pointer . */
UInt32 bitBufPoolSize[IPC_BITS_OUT_MAX_NUM_ALLOC_POOLS];
/**< Size of Pools bitstream buffer. */
Bitstream_BufList freeBitBufList; /**< BitStream buffers to be freed */
IpcBitsOutStats stats; /**< Statistics accumulation member */
IpcBitsOutLink_OutQueueInfo outQueInfo; /**< Output BitStream queue info */
volatile Bool startProcessing; /**< Flag to control start of processing */
} IpcBitsOutLink_Obj;
typedef struct
{
OSA_TskHndl *pTsk;
System_GetLinkInfoCb getLinkInfo;
/**< Function that returns the LINKs output channel configurations */
} System_LinkObj;
//初始化IpcBitsOutLink的数据结构
static Int IpcBitsOutLink_createOutObj(IpcBitsOutLink_Obj * pObj)
{
Int status = OSA_SOK;
Int32 poolId, elemId, bufId;
IHeap_Handle srBitBufHeapHandle;
UInt32 bufSize, numBufs, totBufSize, cacheLineSize;
const UInt32 srIndex = SYSTEM_IPC_SR_CACHED;
Ptr phyAddr;
ipcbitsoutlink_populate_outbuf_pool_size_info(&pObj->createArgs,
&pObj->createArgs.inQueInfo,
&pObj->outQueInfo);
elemId = 0;
//共享区域获取heap的句柄,从堆上分配内存;
srBitBufHeapHandle =SharedRegion_getHeap(srIndex);
OSA_assert(srBitBufHeapHandle != NULL);
//获取cache的一行的size
cacheLineSize = SharedRegion_getCacheLineSize(srIndex);
for (poolId = 0; poolId < pObj->outQueInfo.allocPoolInfo.numPools; poolId++)
{
//建立一个队列
status = OSA_queCreate(&pObj->listElemQue[poolId],
SYSTEM_IPC_BITS_MAX_LIST_ELEM);
OSA_assert(status == OSA_SOK);
bufSize =
OSA_align(pObj->outQueInfo.allocPoolInfo.bufPoolInfo[poolId].
bufSize, cacheLineSize);
numBufs = pObj->outQueInfo.allocPoolInfo.bufPoolInfo[poolId].numBufs;
totBufSize = bufSize * numBufs;
OSA_printf ("###Bit buff of size from the SR # %d : %d\n", srIndex, totBufSize);
//分配队列的内存,
pObj->bitBufPoolPtr[poolId] =
Memory_alloc(srBitBufHeapHandle, totBufSize, cacheLineSize, NULL);
OSA_assert(pObj->bitBufPoolPtr[poolId] != NULL);
OSA_printf("IPC_BITSOUT:BitBuffer Alloc.PoolID:%d,Size:0x%X",
poolId,totBufSize);
//虚拟内存到物理内存映射
phyAddr = IpcBitsOutLink_MapUsrVirt2Phy(pObj->bitBufPoolPtr[poolId]);
pObj->bitBufPoolSize[poolId] = totBufSize;
//给队列中的每个元素分配内存
for (bufId = 0; bufId < numBufs; bufId++)
{
SystemIpcBits_ListElem *listElem;
OSA_assert(elemId < SYSTEM_IPC_BITS_MAX_LIST_ELEM);
listElem = pObj->listElem[elemId];
elemId++;
SYSTEM_IPC_BITS_SET_BUFOWNERPROCID(listElem->bufState);
SYSTEM_IPC_BITS_SET_BUFSTATE(listElem->bufState,
IPC_BITBUF_STATE_FREE);
listElem->bitBuf.addr =
(Ptr) (((UInt32) (pObj->bitBufPoolPtr[poolId])) +
(bufSize * bufId));
if (phyAddr)
{
listElem->bitBuf.phyAddr =
(UInt32) ((UInt32) (phyAddr) + (bufSize * bufId));
}
listElem->bitBuf.allocPoolID = poolId;
listElem->bitBuf.bufSize = bufSize;
listElem->bitBuf.fillLength = 0;
listElem->bitBuf.mvDataFilledSize = 0;
listElem->bitBuf.startOffset = 0;
listElem->bitBuf.bottomFieldBitBufSize = 0;
listElem->bitBuf.doNotDisplay = FALSE;
listElem->srBufPtr = SharedRegion_getSRPtr(listElem->bitBuf.addr,
srIndex);
OSA_assert(listElem->srBufPtr != IPC_LINK_INVALID_SRPTR);
//将元素压入到队列
status =
OSA_quePut(&pObj->listElemQue[poolId], (Int32) listElem,
OSA_TIMEOUT_NONE);
OSA_assert(status == OSA_SOK);
}
}
return status;
}
// IpcBitsOutLink_getEmptyVideoBitStreamBufs函数的作用是从IpcBitsOutLink的队列中获取一个空的buff
Int32 IpcBitsOutLink_getEmptyVideoBitStreamBufs(UInt32 linkId,
Bitstream_BufList *bufList,
IpcBitsOutLinkHLOS_BitstreamBufReqInfo *reqInfo)
{
OSA_TskHndl * pTsk;
IpcBitsOutLink_Obj * pObj;
Int status;
OSA_assert(bufList != NULL);
if (!((linkId >= SYSTEM_HOST_LINK_ID_IPC_BITS_OUT_0)
&&
(linkId < (SYSTEM_HOST_LINK_ID_IPC_BITS_OUT_0 + IPC_BITS_OUT_LINK_OBJ_MAX))))
{
return IPC_BITSOUT_LINK_E_INVALIDLINKID;
}
pTsk = System_getLinkTskHndl(linkId);
pObj = pTsk->appData;
bufList->numBufs = 0;
if (pObj->startProcessing)
{
IpcBitsOutLink_releaseBitBufs(pObj);
status = IpcBitsOutLink_getEmptyBufs(pObj,bufList,reqInfo);
}
else
{
status = IPC_BITSOUT_LINK_S_SUCCESS;
}
return status;
}
// IpcBitsOutLink_putFullVideoBitStreamBufs函数的作用是将Bitstream_BufList数据传递到下一个link;
Int32 IpcBitsOutLink_putFullVideoBitStreamBufs(UInt32 linkId,
Bitstream_BufList *bufList)
{
OSA_TskHndl * pTsk;
IpcBitsOutLink_Obj * pObj;
Int status;
OSA_assert(bufList != NULL);
if (!((linkId >= SYSTEM_HOST_LINK_ID_IPC_BITS_OUT_0)
&&
(linkId < (SYSTEM_HOST_LINK_ID_IPC_BITS_OUT_0 + IPC_BITS_OUT_LINK_OBJ_MAX))))
{
return IPC_BITSOUT_LINK_E_INVALIDLINKID;
}
//通过linkId获取link任务的数据
pTsk = System_getLinkTskHndl(linkId);
//获取link的appData,将pObj指向该link的appData内存地址;
pObj = pTsk->appData;
status = IpcBitsOutLink_putFullBufs(pObj,bufList);
return status;
}
//数据如何从IpcBitsOutLink传递到VideoM3
static
Int32 IpcBitsOutLink_putFullBufs(IpcBitsOutLink_Obj *pObj,
Bitstream_BufList *pBufList)
{
SystemIpcBits_ListElem *pListElem;
Bitstream_Buf *pBitBuf;
Bitstream_BufList freeBitBufList;
Bool putDone = FALSE;
Int32 bufId;
UInt32 curTime;
freeBitBufList.numBufs = 0;
curTime = OSA_getCurTimeInMsec();
for (bufId = 0; bufId < pBufList->numBufs; bufId++)
{
pBitBuf = pBufList->bufs[bufId];
curTime = pBitBuf->timeStamp = Get_timeStamp(pBitBuf->channelNum); // for playback side avsync support
// OSA_printf(" A8 IPC_BITS_OUT : TS = %d !!!\n", pBitBuf->timeStamp); //test1
//获取pBufList的每一个元素
pListElem = (SystemIpcBits_ListElem *)pBitBuf;
//判断指针是否一致
OSA_assert(SharedRegion_getPtr(pListElem->srBufPtr) ==
pBitBuf->addr);
//如果数据长度为0,直接将数据归还到队列
if (0 == pBitBuf->fillLength)
{
/* filled length of 0 indicates application
* did not fill any data in this buffer.
* Free it immediately */
#ifdef SYSTEM_DEBUG_IPC_RT
OSA_printf(" IPC_OUT: Dropping bitbuf\n");
#endif
OSA_assert(freeBitBufList.numBufs <
VIDBITSTREAM_MAX_BITSTREAM_BUFS);
//归还buff
freeBitBufList.bufs[freeBitBufList.numBufs] = pBitBuf;
freeBitBufList.numBufs++;
pObj->stats.droppedCount++;
continue;
}
else
{
pObj->stats.recvCount++;
OSA_assert(SYSTEM_IPC_BITS_GET_BUFSTATE(pListElem->bufState)
== IPC_BITBUF_STATE_FREE);
OSA_assert(SYSTEM_IPC_BITS_GET_BUFOWNERPROCID(pListElem->bufState)
== System_getSelfProcId());
pListElem->ipcPrivData = (Ptr) curTime;
SYSTEM_IPC_BITS_SET_BUFSTATE(pListElem->bufState,
IPC_BITBUF_STATE_ALLOCED);
//将数据传递给下一个link,ListMP :在多个核之间共享一个List指针队列;
IpcBitsOutLink_listMPPut(pObj, pListElem);
putDone = TRUE;
}
}
if (freeBitBufList.numBufs)
{
IpcBitsOutLink_putEmptyBufs(pObj, &freeBitBufList);
}
if (putDone && (pObj->createArgs.baseCreateParams.notifyNextLink))
{
//给下一个link发送通知,
这里是给videoM3的ipcBitsInLink发送消息
System_ipcSendNotify(pObj->createArgs.baseCreateParams.outQueParams[0].
nextLink);
}
if (!putDone)
{
pObj->stats.numNoFullBufCount++;
if ((pObj->stats.numNoFullBufCount % IPC_BITSOUT_STATS_WARN_INTERVAL) == 0)
{
#ifdef DEBUG_IPC_BITS
OSA_printf("IPCBITSOUT:!!!WARNING.!!! NO FULL BUF AVAILABLE. OCCURENCE COUNT:[%d]",
pObj->stats.numNoFullBufCount);
#endif
}
}
return IPC_BITSOUT_LINK_S_SUCCESS;
}
//
static
Int32 IpcBitsOutLink_listMPPut(IpcBitsOutLink_Obj * pObj,
SystemIpcBits_ListElem * pListElem)
{
Int32 status = IPC_BITSOUT_LINK_S_SUCCESS;
SYSTEM_IPC_BITS_SET_BUFSTATE(pListElem->bufState, IPC_BITBUF_STATE_OUTQUE);
IpcBitsOutLink_doPrePutCacheOp(pObj, pListElem);
//挂在link的队列末尾
status = ListMP_putTail(pObj->listMPOutHndl, (ListMP_Elem *) pListElem);
OSA_assert(status == ListMP_S_SUCCESS);
return IPC_BITSOUT_LINK_S_SUCCESS;
}
pcBitsInVideoM3Id
Main函数:link起来后等待消息,
Void IpcBitsInLink_tskMain(struct Utils_TskHndl * pTsk, Utils_MsgHndl * pMsg)
{
UInt32 cmd = Utils_msgGetCmd(pMsg);
Bool ackMsg, done;
Int32 status;
IpcBitsInLink_Obj *pObj = (IpcBitsInLink_Obj *) pTsk->appData;
if (cmd != SYSTEM_CMD_CREATE)
{
Utils_tskAckOrFreeMsg(pMsg, FVID2_EFAIL);
return;
}
status = IpcBitsInLink_create(pObj, Utils_msgGetPrm(pMsg));
Utils_tskAckOrFreeMsg(pMsg, status);
if (status != FVID2_SOK)
return;
done = FALSE;
ackMsg = FALSE;
while (!done)
{
status = Utils_tskRecvMsg(pTsk, &pMsg, BIOS_WAIT_FOREVER);
if (status != FVID2_SOK)
break;
cmd = Utils_msgGetCmd(pMsg);
switch (cmd)
{
case SYSTEM_CMD_DELETE:
done = TRUE;
ackMsg = TRUE;
break;
//等待A8 IpcBitsOutLink,发送信号,
case SYSTEM_CMD_NEW_DATA:
Utils_tskAckOrFreeMsg(pMsg, status);
IpcBitsInLink_processBitBufs(pObj);
break;
case SYSTEM_CMD_STOP:
IpcBitsInLink_stop(pObj);
Utils_tskAckOrFreeMsg(pMsg, status);
break;
default:
Utils_tskAckOrFreeMsg(pMsg, status);
break;
}
}
IpcBitsInLink_delete(pObj);
#ifdef SYSTEM_DEBUG_IPC_BITS_IN
Vps_printf(" %d: IPC_BITS_IN : Delete Done !!!\n", Utils_getCurTimeInMsec());
#endif
if (ackMsg && pMsg != NULL)
Utils_tskAckOrFreeMsg(pMsg, status);
return;
}
信号的发送,A8的IpcBitsOutLink中调用它发送信号;
Void IpcBitsInLink_notifyCb(Utils_TskHndl * pTsk)
{
IpcBitsInLink_Obj *pObj = (IpcBitsInLink_Obj *) pTsk->appData;
IpcBitsInLink_reconfigPrdObj(pObj, IPC_BITS_IN_LINK_DONE_PERIOD_MS);
Utils_tskSendCmd(pTsk, SYSTEM_CMD_NEW_DATA);
}
//
Int32 IpcBitsInLink_processBitBufs(IpcBitsInLink_Obj * pObj)
{
Bitstream_Buf *pBitBuf;
SystemIpcBits_ListElem *pListElem;
UInt32 numBitBufs;
Int32 status;
UInt32 curTime;
numBitBufs = 0;
curTime = Utils_getCurTimeInMsec();
while (1)
{
//获取Buff
pListElem = ListMP_getHead(pObj->listMPOutHndl);
if (pListElem == NULL)
break;
//转化到Bitbuf
IpcBitsInLink_getBitBuf(pObj, pListElem, &pBitBuf);
UTILS_assert(SYSTEM_IPC_BITS_GET_BUFSTATE(pListElem->bufState)
== IPC_BITBUF_STATE_OUTQUE);
pBitBuf->reserved[0] = curTime;
SYSTEM_IPC_BITS_SET_BUFOWNERPROCID(pListElem->bufState);
SYSTEM_IPC_BITS_SET_BUFSTATE(pListElem->bufState,
IPC_BITBUF_STATE_DEQUEUED);
pObj->stats.recvCount++;
//压入到队列,同一个核使用Utils_quePut函数
status = Utils_quePut(&pObj->outBitBufQue, pBitBuf, BIOS_NO_WAIT);
UTILS_assert(status == FVID2_SOK);
numBitBufs++;
}
#ifdef SYSTEM_DEBUG_IPC_RT
Vps_printf(" %d: IPC_BITS_IN : Recevived %d bitbufs !!!\n",
Utils_getCurTimeInMsec(), numBitBufs);
#endif
//往下一个link发送数据
if (numBitBufs && pObj->createArgs.baseCreateParams.notifyNextLink)
{
UTILS_assert(pObj->createArgs.baseCreateParams.numOutQue == 1);
System_sendLinkCmd(pObj->createArgs.baseCreateParams.outQueParams[0].
nextLink, SYSTEM_CMD_NEW_DATA);
}
return IPC_BITS_IN_LINK_S_SUCCESS;
}