例子:从A8送一帧jpeg图片到videoM3解码,然后在将解码的数据传递到A8, 这个流程涉及的link源码如下:
dm8148 link之间数据传递 1)在A8上调用IpcBitsOutLink_getEmptyVideoBitStreamBufs从IpcBitsOutLink获取buff;然后调用IpcBitsOutLink_putFullVideoBitStreamBufs将数据送入到IpcBitsOutLink; 1.1)IpcBitsOutLink A8调用IpcBitsOutLink将压缩数据(jpeg,mpeg4,h264)送入到videoM3;首先在/src_linux\links\system的system_common.c中调用IpcBitsOutLink_init函数; //system_init函数在app初始化时调用; Int32 System_init() { Int32 status; #ifdef SYSTEM_DEBUG OSA_printf ( " %u: SYSTEM: System Common Init in progress !!!\n", OSA_getCurTimeInMsec()); #endif memset(&gSystem_objCommon, 0, sizeof(gSystem_objCommon)); System_ipcInit(); IpcBitsInLink_init(); IpcBitsOutLink_init(); IpcFramesInLink_init(); IpcFramesOutLink_init(); ........... status = OSA_mbxCreate(&gSystem_objCommon.mbx); UTILS_assert( status==OSA_SOK); SystemLink_init(); #ifdef SYSTEM_DEBUG OSA_printf ( " %u: SYSTEM: System Common Init Done !!!\n", OSA_getCurTimeInMsec()); #endif return status; } 1.2)IpcBitsOutLink_init函数 Int32 IpcBitsOutLink_init() { Int32 status; System_LinkObj linkObj; UInt32 ipcBitsOutId; IpcBitsOutLink_Obj *pObj; char tskName[32]; UInt32 procId = System_getSelfProcId(); OSA_COMPILETIME_ASSERT(offsetof(SystemIpcBits_ListElem, bitBuf) == 0); OSA_COMPILETIME_ASSERT(offsetof(Bitstream_Buf, reserved) == 0); OSA_COMPILETIME_ASSERT(sizeof(((Bitstream_Buf *) 0)->reserved) == sizeof(ListMP_Elem)); for (ipcBitsOutId = 0; ipcBitsOutId < IPC_BITS_OUT_LINK_OBJ_MAX; ipcBitsOutId++) { pObj = &gIpcBitsOutLink_obj[ipcBitsOutId]; memset(pObj, 0, sizeof(*pObj)); pObj->tskId = SYSTEM_MAKE_LINK_ID(procId, SYSTEM_LINK_ID_IPC_BITS_OUT_0) + ipcBitsOutId; linkObj.pTsk = &pObj->tsk; linkObj.getLinkInfo = IpcBitsOutLink_getLinkInfo; System_registerLink(pObj->tskId, &linkObj); OSA_SNPRINTF(tskName, "IPC_BITS_OUT%d", ipcBitsOutId); //注册通知 System_ipcRegisterNotifyCb(pObj->tskId, IpcBitsOutLink_notifyCb); //初始化ListMP IpcBitsOutLink_initListMP(pObj); status = OSA_tskCreate(&pObj->tsk, IpcBitsOutLink_tskMain, IPC_LINK_TSK_PRI, IPC_LINK_TSK_STACK_SIZE, 0, pObj); OSA_assert(status == OSA_SOK); } return status; } 1.3)IpcBitsOutLink_tskMain函数 Int IpcBitsOutLink_tskMain(struct OSA_TskHndl * pTsk, OSA_MsgHndl * pMsg, Uint32 curState) { UInt32 cmd = OSA_msgGetCmd(pMsg); Bool ackMsg, done; Int32 status = IPC_BITSOUT_LINK_S_SUCCESS; //appData中保存的是和link相关的参数 IpcBitsOutLink_Obj *pObj = (IpcBitsOutLink_Obj *) pTsk->appData; //SYSTEM_CMD_CREATE为System_linkCreate函数的命令号,如果cmd!=SYSTEM_CMD_CREATE,主函数退出??? if (cmd != SYSTEM_CMD_CREATE) { OSA_tskAckOrFreeMsg(pMsg, OSA_EFAIL); return status; } status = IpcBitsOutLink_create(pObj, OSA_msgGetPrm(pMsg)); OSA_tskAckOrFreeMsg(pMsg, status); if (status != OSA_SOK) return status; done = FALSE; ackMsg = FALSE; while (!done) { status = OSA_tskWaitMsg(pTsk, &pMsg); if (status != OSA_SOK) break; cmd = OSA_msgGetCmd(pMsg); switch (cmd) { case SYSTEM_CMD_DELETE: done = TRUE; ackMsg = TRUE; break; case SYSTEM_IPC_CMD_RELEASE_FRAMES: OSA_tskAckOrFreeMsg(pMsg, status); #ifdef SYSTEM_DEBUG_IPC_RT OSA_printf(" %d: IPC_BITS_OUT : Received Notify !!!\n", OSA_getCurTimeInMsec()); #endif IpcBitsOutLink_releaseBitBufs(pObj); break; case SYSTEM_CMD_START: //link start IpcBitsOutLink_start(pObj); OSA_tskAckOrFreeMsg(pMsg, status); break; case SYSTEM_CMD_STOP: //link stop IpcBitsOutLink_stop(pObj); OSA_tskAckOrFreeMsg(pMsg, status); break; default: OSA_tskAckOrFreeMsg(pMsg, status); break; } } IpcBitsOutLink_delete(pObj); #ifdef SYSTEM_DEBUG_IPC_BITS_OUT OSA_printf(" %d: IPC_BITS_OUT : Delete Done !!!\n", OSA_getCurTimeInMsec()); #endif if (ackMsg && pMsg != NULL) OSA_tskAckOrFreeMsg(pMsg, status); return IPC_BITSOUT_LINK_S_SUCCESS; } 1.4)IpcBitsOutLink_create函数 Int32 IpcBitsOutLink_create(IpcBitsOutLink_Obj * pObj, IpcBitsOutLinkHLOS_CreateParams * pPrm) { Int32 status; UInt32 i; #ifdef SYSTEM_DEBUG_IPC OSA_printf(" %d: IPC_BITS_OUT : Create in progress !!!\n", OSA_getCurTimeInMsec()); #endif memcpy(&pObj->createArgs, pPrm, sizeof(pObj->createArgs)); for (i=0; i<IPC_LINK_BITS_OUT_MAX_NUM_ALLOC_POOLS; i++) { OSA_assert(i < IPC_BITS_OUT_MAX_NUM_ALLOC_POOLS); if(pObj->createArgs.numBufPerCh[i] == 0) pObj->createArgs.numBufPerCh[i] = IPC_BITS_OUT_LINK_MAX_OUT_FRAMES_PER_CH; if(pObj->createArgs.numBufPerCh[i] > IPC_BITS_OUT_LINK_MAX_OUT_FRAMES_PER_CH) { OSA_printf("\n IPCBITSOUTLINK: WARNING: User is asking for %d buffers per CH. But max allowed is %d. \n" " Over riding user requested with max allowed \n\n", pObj->createArgs.numBufPerCh[i], IPC_BITS_OUT_LINK_MAX_OUT_FRAMES_PER_CH ); pObj->createArgs.numBufPerCh[i] = IPC_BITS_OUT_LINK_MAX_OUT_FRAMES_PER_CH; } } //listMP 队列清空 status = System_ipcListMPReset(pObj->listMPOutHndl, pObj->listMPInHndl); OSA_assert(status == OSA_SOK); //分配link的内存 IpcBitsOutLink_createOutObj(pObj); IpcBitsOutLink_initStats(pObj); pObj->startProcessing = FALSE; #ifdef SYSTEM_DEBUG_IPC OSA_printf(" %d: IPC_BITS_OUT : Create Done !!!\n", OSA_getCurTimeInMsec()); #endif return IPC_BITSOUT_LINK_S_SUCCESS; } 1.5)IpcBitsOutLink_createOutObj函数分配该link需要多少内存,link的内存由link自己管理,在建立link时,告诉该link 内存池的个数,每个池中的buff的个数,link自己决定分配多少内存; 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; srBitBufHeapHandle = SharedRegion_getHeap(srIndex); OSA_assert(srBitBufHeapHandle != NULL); 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; //获取Buf的指针 listElem->srBufPtr = SharedRegion_getSRPtr(listElem->bitBuf.addr, srIndex); OSA_assert(listElem->srBufPtr != IPC_LINK_INVALID_SRPTR); //将分配的buff挂在插入list队列,使用时,从队列中取empty buff,比如在A8需要将bit数据拷贝传递到IpcBitsOutLink,调用IpcBitsOutLink_getEmptyVideoBitStreamBufs (IpcBitsOutLink_getEmptyBufs)从队列中取buff; status = OSA_quePut(&pObj->listElemQue[poolId], (Int32) listElem, OSA_TIMEOUT_NONE); OSA_assert(status == OSA_SOK); } } return status; } 1.6)A8中调用该函数将buff传递IpcBitsOutLink 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; } pTsk = System_getLinkTskHndl(linkId); pObj = pTsk->appData; //将buff传递到下一个link status = IpcBitsOutLink_putFullBufs(pObj,bufList); return status; } 1.7)IpcBitsOutLink_putFullBufs 将buff传递到下一个link,注意IpcBitsOutLink_listMPPut,将buff压入到输出队列,然后发送System_ipcSendNotify 发送通知,通知下一个link来取数据; 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);
pListElem = (SystemIpcBits_ListElem *)pBitBuf; OSA_assert(SharedRegion_getPtr(pListElem->srBufPtr) == pBitBuf->addr); 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); 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); //压入到输出队列 IpcBitsOutLink_listMPPut(pObj, pListElem); putDone = TRUE; } } if (freeBitBufList.numBufs) { IpcBitsOutLink_putEmptyBufs(pObj, &freeBitBufList); } if (putDone && (pObj->createArgs.baseCreateParams.notifyNextLink)) { //通知下一个link,调用Notify_sendEvent函数 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; } 1.8)IpcBitsOutLink_listMPPut 函数 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); //cache 多核之间数据拷贝,传递到ipcbitsIn(videoM3) link IpcBitsOutLink_doPrePutCacheOp(pObj, pListElem); status = ListMP_putTail(pObj->listMPOutHndl, (ListMP_Elem *) pListElem); OSA_assert(status == ListMP_S_SUCCESS); return IPC_BITSOUT_LINK_S_SUCCESS; } 1.9)IpcBitsOutLink_doPrePutCacheOp 函数; static Int32 IpcBitsOutLink_doPrePutCacheOp(IpcBitsOutLink_Obj * pObj, SystemIpcBits_ListElem * pListElem) { if (pListElem->bitBuf.fillLength) { Cache_wbInv(pListElem->bitBuf.addr, pListElem->bitBuf.fillLength, Cache_Type_ALL, TRUE); } /* No cache ops done since pListElem is allocated from non-cached memory */ UTILS_assert(SharedRegion_isCacheEnabled(SharedRegion_getId(pListElem)) == FALSE); return IPC_BITSOUT_LINK_S_SUCCESS; } ListMP_putTail 和ListMP_getHead 作用,多核之间用吗?相邻2个核之间的link公用一个ListMp队列吗?ipcBitsOutLink(A8)发送通知Notify_sendEvent告诉ipcBitsInLink(videoM3),在 ListMP队列已经存在数据; ListMP实现了多宿主双向循环链表,即该双向循环链表为多个处理器共同拥有,可以由多个处理器共同维护,共同使用。 ListMP的实现区别于一般的双向循环链表,因此它不仅具有双向循环链表的特性外,还增添了其他的特性,比如以下几点: 1.实现了简单的多宿主协议,支持多个读写者(multi-reader、multi-writee); 2.使用Gate作为内部保护机制,防止多个宿主处理器同时访问该链表; ListMP的实现并未加入通知机制,如果需要的话,可以在外部封装是引入Notify机制来实现;使用ListMP机制来管理的buffers都需要从共享内存区分配,包括从堆内存分配的buffers以及动 态分配的内存。 2)videoM3 systemLink 多核之间数据传递要用到systemlink,以下是videoM3中systemLink的初始化函数;主要有IpcOutM3Link_init()函数和IpcInM3Link_init()函数; mcfw/src_bios6/links_m3video/system ;system_m3video.c Int32 System_init() { Int32 status = FVID2_SOK; #ifdef SYSTEM_DEBUG Vps_printf(" %d: SYSTEM : System Video Init in progress !!!\n", Utils_getCurTimeInMsec()); #endif #ifdef SYSTEM_DEBUG Vps_printf(" %d: SYSTEM : System Video Init Done !!!\n", Utils_getCurTimeInMsec()); #endif IpcOutM3Link_init(); IpcInM3Link_init(); IpcBitsInLink_init(); IpcBitsOutLink_init(); IpcFramesInLink_init(); IpcFramesOutLink_init(); Utils_encdecInit(); //编解码link初始化 System_initLinks(); return status; } 3)IpcBitsInLink(mcfw_bios6) 3.1)初始化函数 Int32 IpcBitsInLink_init() { Int32 status; System_LinkObj linkObj; UInt32 ipcBitsInId; IpcBitsInLink_Obj *pObj; char tskName[32]; UInt32 procId = System_getSelfProcId(); UTILS_COMPILETIME_ASSERT(offsetof(SystemIpcBits_ListElem, bitBuf) == 0); UTILS_COMPILETIME_ASSERT(offsetof(Bitstream_Buf, reserved) == 0); UTILS_COMPILETIME_ASSERT(sizeof(((Bitstream_Buf *) 0)->reserved) == sizeof(ListMP_Elem)); for (ipcBitsInId = 0; ipcBitsInId < IPC_BITS_IN_LINK_OBJ_MAX; ipcBitsInId++) { pObj = &gIpcBitsInLink_obj[ipcBitsInId]; memset(pObj, 0, sizeof(*pObj)); pObj->tskId = SYSTEM_MAKE_LINK_ID(procId, SYSTEM_LINK_ID_IPC_BITS_IN_0) + ipcBitsInId; pObj->state = IPC_BITS_IN_LINK_STATE_INACTIVE; linkObj.pTsk = &pObj->tsk; linkObj.linkGetFullFrames = NULL; linkObj.linkPutEmptyFrames = NULL; linkObj.linkGetFullBitBufs = IpcBitsInLink_getFullBitBufs; linkObj.linkPutEmptyBitBufs = IpcBitsInLink_putEmptyBitBufs; linkObj.getLinkInfo = IpcBitsInLink_getLinkInfo; System_registerLink(pObj->tskId, &linkObj); UTILS_SNPRINTF(tskName, "IPC_BITS_IN%d", ipcBitsInId); System_ipcRegisterNotifyCb(pObj->tskId, IpcBitsInLink_notifyCb); status = Utils_tskCreate(&pObj->tsk, IpcBitsInLink_tskMain, IPC_LINK_TSK_PRI, gIpcBitsInLink_tskStack[ipcBitsInId], IPC_LINK_TSK_STACK_SIZE, pObj, tskName); UTILS_assert(status == FVID2_SOK); } return status; } 3.2)IpcBitsInLink_tskMain 主函数 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; } //ListMP 和队列资源初始化 status = IpcBitsInLink_create(pObj, Utils_msgGetPrm(pMsg)); Utils_tskAckOrFreeMsg(pMsg, status); if (status != FVID2_SOK) return; done = FALSE; ackMsg = FALSE; while (!done) { //接收消息,是接收从ipcbitsOutlink(A8) 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; case SYSTEM_CMD_NEW_DATA: //从IpcInM3 Link获取消息 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; } 3.3)IpcBitsInLink_processBitBufs函数 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) { //获取listElem,多核之间获取数据; pListElem = ListMP_getHead(pObj->listMPOutHndl); if (pListElem == NULL) break; //转化为bitbuff 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++; //压入到输出队列; 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; } 4)VideoM3 declink 4.1)解码link初始化函数 Int32 DecLink_init() { Int32 status; System_LinkObj linkObj; DecLink_Obj *pObj; char name[32]; UInt32 objId; for (objId = 0; objId < DEC_LINK_OBJ_MAX; objId++) { pObj = &gDecLink_obj[objId]; memset(pObj, 0, sizeof(*pObj)); pObj->linkId = SYSTEM_LINK_ID_VDEC_0 + objId; linkObj.pTsk = &pObj->tsk; linkObj.linkGetFullFrames = DecLink_getFullFrames; linkObj.linkPutEmptyFrames = DecLink_putEmptyFrames; linkObj.linkGetFullBitBufs = NULL; linkObj.linkPutEmptyBitBufs = NULL; linkObj.getLinkInfo = DecLink_getInfo; UTILS_SNPRINTF(name, "DEC%d ", objId); System_registerLink(pObj->linkId, &linkObj); status = Utils_tskCreate(&pObj->tsk, DecLink_tskMain, DEC_LINK_TSK_PRI, gDecLink_tskStack[objId], DEC_LINK_TSK_STACK_SIZE, pObj, name); UTILS_assert(status == FVID2_SOK); } return status; } 4.2)DecLink_tskMain 主函数 Void DecLink_tskMain(struct Utils_TskHndl *pTsk, Utils_MsgHndl * pMsg) { UInt32 cmd = Utils_msgGetCmd(pMsg); Bool ackMsg, done; Int32 status; DecLink_Obj *pObj; UInt32 flushCmds[2]; pObj = (DecLink_Obj *) pTsk->appData; if (cmd != SYSTEM_CMD_CREATE) { #ifndef DEC_LINK_SUPRESS_ERROR_AND_RESET DECLINK_INTERNAL_ERROR_LOG(DEC_LINK_E_INVALIDCMD, "Link create should be first cmd." "Received Cmd:%d", cmd); #endif Utils_tskAckOrFreeMsg(pMsg, FVID2_EFAIL); return; } //分配link的内存等资源,创建解码线程(调用该函数DecLink_codecCreateProcessTsk(pObj, tskId);) status = DecLink_codecCreate(pObj, Utils_msgGetPrm(pMsg)); Utils_tskAckOrFreeMsg(pMsg, status); if (status != FVID2_SOK) return; Utils_encdecHdvicpPrfInit(); 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_NEW_DATA: Utils_tskAckOrFreeMsg(pMsg, status); flushCmds[0] = SYSTEM_CMD_NEW_DATA; Utils_tskFlushMsg(pTsk, flushCmds, 1); //link收到数据,调用该函数进行解码 DecLink_codecProcessData(pObj); break; case DEC_LINK_CMD_GET_PROCESSED_DATA: Utils_tskAckOrFreeMsg(pMsg, status); flushCmds[0] = DEC_LINK_CMD_GET_PROCESSED_DATA; Utils_tskFlushMsg(pTsk, flushCmds, 1); DecLink_codecGetProcessedDataMsgHandler(pObj); break; case DEC_LINK_CMD_PRINT_IVAHD_STATISTICS: Utils_tskAckOrFreeMsg(pMsg, status); Utils_encdecHdvicpPrfPrint(); break; case DEC_LINK_CMD_PRINT_STATISTICS: DecLink_printStatistics(pObj, TRUE); Utils_tskAckOrFreeMsg(pMsg, status); break; case DEC_LINK_CMD_PRINT_BUFFER_STATISTICS: Utils_tskAckOrFreeMsg(pMsg, status); DecLink_printBufferStatus(pObj); break; case DEC_LINK_CMD_DISABLE_CHANNEL: { DecLink_ChannelInfo *params; params = (DecLink_ChannelInfo *) Utils_msgGetPrm(pMsg); DecLink_codecDisableChannel(pObj, params); Utils_tskAckOrFreeMsg(pMsg, status); } break; case DEC_LINK_CMD_ENABLE_CHANNEL: { DecLink_ChannelInfo *params; params = (DecLink_ChannelInfo *) Utils_msgGetPrm(pMsg); DecLink_codecEnableChannel(pObj, params); Utils_tskAckOrFreeMsg(pMsg, status); } break; case DEC_LINK_CMD_SET_TRICKPLAYCONFIG: { DecLink_TPlayConfig * params; params = (DecLink_TPlayConfig *) Utils_msgGetPrm(pMsg); DecLink_setTPlayConfig(pObj, params); Utils_tskAckOrFreeMsg(pMsg, status); } break; case SYSTEM_CMD_STOP: DecLink_codecStop(pObj); Utils_tskAckOrFreeMsg(pMsg, status); break; case SYSTEM_CMD_DELETE: DecLink_codecStop(pObj); done = TRUE; ackMsg = TRUE; break; default: Utils_tskAckOrFreeMsg(pMsg, status); break; } } DecLink_codecDelete(pObj); if (ackMsg && pMsg != NULL) Utils_tskAckOrFreeMsg(pMsg, status); return; } 4.3)DecLink_codecProcessData函数从上一个link中获取bit数据,调用videoM3的解码器进行解码; Int32 DecLink_codecProcessData(DecLink_Obj * pObj) { Int32 status; pObj->newDataProcessOnFrameFree = FALSE; DecLink_codecQueueBufsToChQue(pObj); do { status = DecLink_codecSubmitData(pObj); } while (status == FVID2_SOK); return FVID2_SOK; } 4.4)DecLink_codecQueueBufsToChQue调用System_getLinksFullBufs从prelink中获取bit数据,保存在BitStream_Buf结构中; static Int32 DecLink_codecQueueBufsToChQue(DecLink_Obj * pObj) { UInt32 bufId, freeBufNum; Bitstream_Buf *pBuf; System_LinkInQueParams *pInQueParams; Bitstream_BufList bufList; DecLink_ChObj *pChObj; Int32 status; UInt32 curTime; pInQueParams = &pObj->createArgs.inQueParams; System_getLinksFullBufs(pInQueParams->prevLinkId, pInQueParams->prevLinkQueId, &bufList); if (bufList.numBufs) { pObj->inBufGetCount += bufList.numBufs; freeBufNum = 0; curTime = Utils_getCurTimeInMsec(); for (bufId = 0; bufId < bufList.numBufs; bufId++) { pBuf = bufList.bufs[bufId]; pChObj = &pObj->chObj[pBuf->channelNum]; pChObj->inFrameRecvCount++; // pBuf->fid = pChObj->nextFid; if(pChObj->disableChn && pChObj->skipFrame == FALSE) { pChObj->skipFrame = TRUE; } else if((pChObj->disableChn == FALSE) && pChObj->skipFrame) { if(pBuf->isKeyFrame == TRUE) { pChObj->skipFrame = FALSE; } } if (((pChObj->IFrameOnlyDecode) && (!pBuf->isKeyFrame)) || pChObj->skipFrame) { pChObj->inBufSkipCount++; pChObj->inFrameUserSkipCount++; // Drop if not a I frame bufList.bufs[freeBufNum] = pBuf; freeBufNum++; } else { pChObj->totalInFrameCnt++; if (pChObj->totalInFrameCnt > DEC_LINK_STATS_START_THRESHOLD) { pChObj->totalFrameIntervalTime += (curTime - pChObj->prevFrmRecvTime); } else { pChObj->totalFrameIntervalTime = 0; pChObj->totalProcessTime = 0; DecLink_resetStatistics(pObj); } pChObj->prevFrmRecvTime = curTime; //将buff压入队列提供解码器 status = Utils_quePut(&pChObj->inQue, pBuf, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); pChObj->inBufQueCount++; } } if (freeBufNum) { bufList.numBufs = freeBufNum; System_putLinksEmptyBufs(pInQueParams->prevLinkId, pInQueParams->prevLinkQueId, &bufList); pObj->inBufPutCount += freeBufNum; } } return FVID2_SOK; } 4.5)System_getLinksFullBufs函数调用systemLink api(pTsk->linkGetFullBitBufs函数)从上一个link获取bit码流数据 Int32 System_getLinksFullBufs(UInt32 linkId, UInt16 queId, Bitstream_BufList * pBufList) { System_LinkObj *pTsk; linkId = SYSTEM_GET_LINK_ID(linkId); UTILS_assert(linkId < SYSTEM_LINK_ID_MAX); pTsk = &gSystem_objCommon.linkObj[linkId]; if (pTsk->linkGetFullBitBufs != NULL) return pTsk->linkGetFullBitBufs(pTsk->pTsk, queId, pBufList); return FVID2_EFAIL; } 4.6)DecLink_codecSubmitData对bit数据进行解码 static Int32 DecLink_codecSubmitData(DecLink_Obj * pObj) { DecLink_ReqObj *pReqObj; DecLink_ChObj *pChObj; UInt32 chCount,chIdIndex, numProcessCh; Bitstream_Buf *pInBuf; FVID2_Frame *pOutFrame; Int32 status = FVID2_EFAIL, numReqObjPerProcess; UInt32 tskId, i; static UInt32 startChID = 0; System_FrameInfo *pOutFrameInfo; UInt32 curTime = Utils_getCurTimeInMsec(); numProcessCh = 0; chIdIndex = startChID; for (chCount = 0; chCount < pObj->inQueInfo.numCh; chCount++,chIdIndex++) { numReqObjPerProcess = 0; if (chIdIndex >= pObj->inQueInfo.numCh) chIdIndex = 0; pChObj = &pObj->chObj[chIdIndex]; if (Utils_queIsEmpty(&pObj->outObj.bufOutQue. emptyQue[pChObj->allocPoolID])) { pObj->newDataProcessOnFrameFree = TRUE; } while(numReqObjPerProcess < pChObj->numReqObjPerProcess) { numReqObjPerProcess++; status = Utils_queGet(&pObj->reqQue, (Ptr *) & pReqObj, 1, BIOS_NO_WAIT); if (UTILS_ISERROR(status)) { break; } pObj->reqQueCount++; UTILS_assert(DEC_LINK_MAX_REQ >= pObj->reqQueCount); tskId = pObj->ch2ProcessTskId[chIdIndex]; if (pChObj->algObj.algCreateParams.fieldMergeDecodeEnable) { /* pReqObj->OutFrameList.numFrames should be set to 2 once */ /* codec has support to consume 2 output pointers rather than */ /* just one pointer with 2 contigous fields in field merged */ /* interlaced decode use case. */ pReqObj->OutFrameList.numFrames = 1; } else { pReqObj->OutFrameList.numFrames = 1; } if ((status == FVID2_SOK) && (pChObj->inBufQueCount) && (Utils_queGetQueuedCount(&pObj->outObj.bufOutQue.emptyQue[pChObj-> allocPoolID]) >= pReqObj->OutFrameList.numFrames) && !(Utils_queIsFull(&pObj->decProcessTsk[tskId].processQue))) { for (i=0; i<pReqObj->OutFrameList.numFrames; i++) { pOutFrame = NULL; status = Utils_bufGetEmptyFrameExt(&pObj->outObj.bufOutQue, &pOutFrame, pObj->outObj.ch2poolMap[chIdIndex], BIOS_NO_WAIT); if (pOutFrame) { declink_codec_init_outframe(pObj, chIdIndex, pOutFrame); pReqObj->OutFrameList.frames[i] = pOutFrame; } else { break; } } if ((status == FVID2_SOK) && (pOutFrame)) { //获取待解码的数据 Utils_queGet(&pChObj->inQue, (Ptr *) & pInBuf, 1, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); pReqObj->InBuf = pInBuf; pChObj->inBufQueCount--; for (i=0; i<pReqObj->OutFrameList.numFrames; i++) { pReqObj->OutFrameList.frames[i]->channelNum = pInBuf->channelNum; //pInBuf->timeStamp = curTime; pReqObj->OutFrameList.frames[i]->timeStamp= pInBuf->timeStamp; pOutFrameInfo = (System_FrameInfo *) pReqObj->OutFrameList.frames[i]->appData; pOutFrameInfo->ts64 = (UInt32)pInBuf->upperTimeStamp; pOutFrameInfo->ts64 <<= 32; pOutFrameInfo->ts64 = pOutFrameInfo->ts64 | ((UInt32)pInBuf->lowerTimeStamp); } numProcessCh++; //插入到解码处理队列 status = Utils_quePut(&pObj->decProcessTsk[tskId].processQue, pReqObj, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); pChObj->processReqestCount++; } else { status = Utils_quePut(&pObj->reqQue, pReqObj, BIOS_NO_WAIT); startChID = chIdIndex; UTILS_assert(status == FVID2_SOK); pObj->reqQueCount--; status = FVID2_EFAIL; continue; } } else { status = Utils_quePut(&pObj->reqQue, pReqObj, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); pObj->reqQueCount--; startChID = chIdIndex; status = FVID2_EFAIL; if (Utils_queIsEmpty(&pObj->outObj.bufOutQue. emptyQue[pChObj->allocPoolID])) { pObj->newDataProcessOnFrameFree = TRUE; } } } } return status; } 4.7)DecLink_codecCreateProcessTsk函数 该函数为解码任务函数;从pObj->decProcessTsk[tskId].processQue队列中获取数据,然后进行解码; static Void DecLink_codecProcessTskFxn(UArg arg1, UArg arg2) { Int32 status, chId, i, j; DecLink_Obj *pObj; DecLink_ChObj *pChObj; DecLink_ReqObj *pReqObj; FVID2_FrameList freeFrameList; UInt32 tskId; pObj = (DecLink_Obj *) arg1; tskId = (UInt32) arg2; while (pObj->state != SYSTEM_LINK_STATE_STOP) { pObj->reqObjBatch[tskId].numReqObjsInBatch = 0; status = DEC_LINK_S_SUCCESS; //从队列中获取待解码的数据 status = Utils_queGet(&pObj->decProcessTsk[tskId].processQue, (Ptr *) & pReqObj, 1, BIOS_WAIT_FOREVER); if (!UTILS_ISERROR(status)) { status = DecLink_PrepareBatch (pObj, tskId, pReqObj, &pObj->reqObjBatch[tskId]); if (UTILS_ISERROR(status)) { UTILS_warn("DEC : IVAHDID : %d ENCLINK:ERROR in " "DecLink_SubmitBatch.Status[%d]", tskId, status); } else { /*Log Batch size statistics*/ pObj->batchStatistics[tskId].numBatchesSubmitted++; pObj->batchStatistics[tskId].currentBatchSize = pObj-> reqObjBatch[tskId].numReqObjsInBatch; if (pObj->batchStatistics[tskId].maxAchievedBatchSize < pObj->batchStatistics[tskId].currentBatchSize) { pObj->batchStatistics[tskId].maxAchievedBatchSize = pObj->batchStatistics[tskId].currentBatchSize; } pObj->batchStatistics[tskId].aggregateBatchSize = pObj->batchStatistics[tskId].aggregateBatchSize + pObj->batchStatistics[tskId].currentBatchSize; pObj->batchStatistics[tskId].averageBatchSize = pObj->batchStatistics[tskId].aggregateBatchSize / pObj->batchStatistics[tskId].numBatchesSubmitted; } } freeFrameList.numFrames = 0; if (pObj->reqObjBatch[tskId].numReqObjsInBatch) { /*Its made sure that for every batch created all ReqObj have the same codec. And every Request Batch has atleast one ReqObj */ chId = pObj->reqObjBatch[tskId].pReqObj[0]->InBuf->channelNum; pChObj = &pObj->chObj[chId]; switch (pChObj->algObj.algCreateParams.format) { case IVIDEO_H264BP: case IVIDEO_H264MP: case IVIDEO_H264HP: status = Declink_h264DecodeFrameBatch(pObj, &pObj->reqObjBatch[tskId], &freeFrameList, tskId); if (UTILS_ISERROR(status)) { #ifndef DEC_LINK_SUPRESS_ERROR_AND_RESET /* UTILS_warn("DECLINK:ERROR in " "Declink_h264DecodeFrameBatch.Status[%d]", status); */ #endif } break; case IVIDEO_MPEG4SP: case IVIDEO_MPEG4ASP: status = Declink_mpeg4DecodeFrameBatch(pObj, &pObj->reqObjBatch[tskId], &freeFrameList); if (UTILS_ISERROR(status)) { #ifndef DEC_LINK_SUPRESS_ERROR_AND_RESET UTILS_warn("DECLINK:ERROR in " "Declink_mpeg4DecodeFrameBatch.Status[%d]", status); #endif } break; case IVIDEO_MJPEG: //调用该函数进行解码 status = Declink_jpegDecodeFrameBatch(pObj, &pObj->reqObjBatch[tskId], &freeFrameList); if (UTILS_ISERROR(status)) { UTILS_warn("DECLINK:ERROR in " "Declink_jpegDecodeFrameBatch.Status[%d]", status); } break; default: UTILS_assert(FALSE); } } for (i = 0; i < pObj->reqObjBatch[tskId].numReqObjsInBatch; i++) { pReqObj = pObj->reqObjBatch[tskId].pReqObj[i]; for (j = 0; j < pReqObj->OutFrameList.numFrames; j++) { FVID2_Frame *displayFrame; DecLink_codecGetDisplayFrame(pObj, pReqObj->OutFrameList.frames[j], &freeFrameList, &displayFrame); pReqObj->OutFrameList.frames[j] = displayFrame; } //将解码后的数据插入到队列,主函数会调用DecLink_codecGetProcessedDataMsgHandler函数对数据进行处理,发给下一个link; status = Utils_quePut(&pObj->processDoneQue, pReqObj, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); } DecLink_codecFreeProcessedFrames(pObj, &freeFrameList); } return; } 4.8)jpeg解码函数(Declink_jpegDecodeFrameBatch)如下: Int32 Declink_jpegDecodeFrameBatch(DecLink_Obj * pObj, DecLink_ReqBatch * pReqObjBatch, FVID2_FrameList * freeFrameList) { int error = XDM_EFAIL, reqObjIdx, chId; Int32 i, freeBufIdx, prosIdx; IJPEGVDEC_InArgs *inArgs; IJPEGVDEC_OutArgs *outArgs; XDM2_BufDesc *inputBufDesc; XDM2_BufDesc *outputBufDesc; IJPEGVDEC_Handle handle; IALG_Fxns *fxns = NULL; FVID2_Frame *outFrame = NULL; IVIDEO2_BufDesc *displayBufs = NULL; UInt32 bytesConsumed; DecLink_ReqObj *pReqObj; DecLink_ChObj *pChObj; System_FrameInfo *pFrameInfo; /*Make sure that the Req Object is not empty*/ UTILS_assert (pReqObjBatch->numReqObjsInBatch > 0); for (reqObjIdx = 0; reqObjIdx < pReqObjBatch->numReqObjsInBatch; reqObjIdx++) { pReqObj = pReqObjBatch->pReqObj[reqObjIdx]; chId = pReqObj->InBuf->channelNum; pChObj = &pObj->chObj[chId]; inArgs = &pChObj->algObj.u.jpegAlgIfObj.inArgs; outArgs = &pChObj->algObj.u.jpegAlgIfObj.outArgs; inputBufDesc = &pChObj->algObj.u.jpegAlgIfObj.inBufs; outputBufDesc = &pChObj->algObj.u.jpegAlgIfObj.outBufs; handle = pChObj->algObj.u.jpegAlgIfObj.algHandle; UTILS_assert(handle != NULL); fxns = (IALG_Fxns *) handle->fxns; //IRESMAN_HDVICP2_EarlyAcquire((IALG_Handle) handle, // pChObj->algObj.u.jpegAlgIfObj.ivaChID); bytesConsumed = 0; for (prosIdx=0; prosIdx< pReqObj->OutFrameList.numFrames; prosIdx++) { /*----------------------------------------------------------------*/ /* Initialize the input ID in input arguments to the bufferid of */ /* buffer element returned from getfreebuffer() function. */ /*----------------------------------------------------------------*/ /* inputID & numBytes need to update before every decode call */ if (FALSE == outArgs->viddecOutArgs.outBufsInUseFlag) { outFrame = pReqObj->OutFrameList.frames[prosIdx]; } else { UTILS_assert(NULL != pChObj->algObj.prevOutFrame); /* Previous buffer was in use. Free the current outBuf */ outFrame = pChObj->algObj.prevOutFrame; freeFrameList->frames[freeFrameList->numFrames] = pReqObj->OutFrameList.frames[prosIdx]; pChObj->numBufsInCodec--; freeFrameList->numFrames++; } inArgs->viddecInArgs.inputID = (UInt32) outFrame; inArgs->viddecInArgs.numBytes = pReqObj->InBuf->fillLength - bytesConsumed; for (i = 0; i < inputBufDesc->numBufs; i++) { /* Set proper buffer addresses for bitstreamn data */ /*---------------------------------------------------------------*/ inputBufDesc->descs[i].buf = (XDAS_Int8 *) pReqObj->InBuf->addr + bytesConsumed; inputBufDesc->descs[i].bufSize.bytes = pReqObj->InBuf->bufSize; } for (i = 0; i < outputBufDesc->numBufs; i++) { /* Set proper buffer addresses for Frame data */ /*------------------------------------------------------------*/ if (pChObj->algObj.algCreateParams.tilerEnable) { outputBufDesc->descs[i].buf = (Ptr) Utils_tilerAddr2CpuAddr((UInt32) (outFrame->addr[0][i])); } else { outputBufDesc->descs[i].buf = outFrame->addr[0][i]; } } fxns->algActivate((IALG_Handle) handle); //调用visa api进行jpeg解码 error = handle->fxns->ividdec.process((IVIDDEC3_Handle) handle, inputBufDesc, outputBufDesc, (IVIDDEC3_InArgs *) inArgs, (IVIDDEC3_OutArgs *) outArgs); fxns->algDeactivate((IALG_Handle) handle); bytesConsumed = outArgs->viddecOutArgs.bytesConsumed; if (error != XDM_EOK) { DECLINK_INTERNAL_ERROR_LOG(error, "ALGPROCESS FAILED:STATUS"); } pChObj->algObj.prevOutFrame = outFrame; pReqObj->status = error; pReqObj->OutFrameList.frames[prosIdx] = NULL; UTILS_assert(outArgs->viddecOutArgs.displayBufsMode == IVIDDEC3_DISPLAYBUFS_EMBEDDED); displayBufs = &(outArgs->viddecOutArgs.displayBufs.bufDesc[0]); if ((outArgs->viddecOutArgs.outputID[0] != 0) && (displayBufs->numPlanes)) { XDAS_Int8 *pExpectedBuf; pReqObj->OutFrameList.frames[prosIdx] = (FVID2_Frame *) outArgs->viddecOutArgs.outputID[0]; if (pChObj->algObj.algCreateParams.tilerEnable) { pExpectedBuf = (Ptr) Utils_tilerAddr2CpuAddr( (UInt32) pReqObj->OutFrameList.frames[prosIdx]->addr[0][0]); } else { pExpectedBuf = pReqObj->OutFrameList.frames[prosIdx]->addr[0][0]; } UTILS_assert(displayBufs->planeDesc[0].buf == pExpectedBuf); /* Enable this code once SysTemFrameInfo is updated with support * for storing frame resolution info */ pFrameInfo = (System_FrameInfo *) pReqObj->OutFrameList.frames[prosIdx]->appData; { UTILS_assert(pFrameInfo != NULL); pFrameInfo->rtChInfo.width = displayBufs->activeFrameRegion.bottomRight.x - displayBufs->activeFrameRegion.topLeft.x; pFrameInfo->rtChInfo.height = displayBufs->activeFrameRegion.bottomRight.y - displayBufs->activeFrameRegion.topLeft.y; pFrameInfo->rtChInfo.pitch[0] = displayBufs->imagePitch[0]; pFrameInfo->rtChInfo.pitch[1] = displayBufs->imagePitch[1]; pFrameInfo->rtChInfoUpdate = TRUE; } pReqObj->OutFrameList.frames[prosIdx]->fid = Utils_encdecMapXDMContentType2FVID2FID(displayBufs-> contentType); } freeBufIdx = 0; while (outArgs->viddecOutArgs.freeBufID[freeBufIdx] != 0) { freeFrameList->frames[freeFrameList->numFrames] = (FVID2_Frame *) outArgs->viddecOutArgs.freeBufID[freeBufIdx]; freeFrameList->numFrames++; pChObj->numBufsInCodec--; freeBufIdx++; } } } return (error); } 4.9)DecLink_codecGetProcessedDataMsgHandler函数功能获取解码后的数据,该函数在DecLink_tskMain中调用; Int32 DecLink_codecGetProcessedDataMsgHandler(DecLink_Obj * pObj) { Int32 status; status = DecLink_codecGetProcessedData(pObj); UTILS_assert(status == FVID2_SOK); return DEC_LINK_S_SUCCESS; } 4.10)DecLink_codecGetProcessedData 处理解码后的数据,发给下一个link static Int32 DecLink_codecGetProcessedData(DecLink_Obj * pObj) { Bitstream_BufList inBufList; FVID2_FrameList outFrameList; FVID2_FrameList outFrameSkipList; UInt32 chId, sendCmd; System_LinkInQueParams *pInQueParams; DecLink_ChObj *pChObj; DecLink_ReqObj *pReqObj; Int32 status, j; UInt32 curTime; sendCmd = FALSE; inBufList.numBufs = 0; inBufList.appData = NULL; outFrameList.numFrames = 0; outFrameSkipList.numFrames = 0; curTime = Utils_getCurTimeInMsec(); while(!Utils_queIsEmpty(&pObj->processDoneQue) && (inBufList.numBufs < (VIDBITSTREAM_MAX_BITSTREAM_BUFS - 1)) && (outFrameList.numFrames < (FVID2_MAX_FVID_FRAME_PTR - 1))) { //获取解码后的数据 status = Utils_queGet(&pObj->processDoneQue, (Ptr *) & pReqObj, 1, BIOS_NO_WAIT); if (status != FVID2_SOK) { break; } UTILS_assert(pReqObj->InBuf != NULL); chId = pReqObj->InBuf->channelNum; pChObj = &pObj->chObj[chId]; //if (pChObj->totalInFrameCnt > DEC_LINK_STATS_START_THRESHOLD) { if (curTime > pReqObj->InBuf->timeStamp) { pChObj->totalProcessTime += (curTime - pReqObj->InBuf->timeStamp); } } pChObj->getProcessedBufCount++; pChObj->outFrameCount++; inBufList.bufs[inBufList.numBufs] = pReqObj->InBuf; inBufList.numBufs++; for (j = 0; j < pReqObj->OutFrameList.numFrames; j++) { if (pReqObj->OutFrameList.frames[j]) { UTILS_assert(pReqObj->InBuf->channelNum == pReqObj->OutFrameList.frames[j]->channelNum); UTILS_assert(pChObj->allocPoolID < UTILS_BUF_MAX_ALLOC_POOLS); pChObj->trickPlayObj.skipFrame = Utils_doSkipFrame(&(pChObj->trickPlayObj.frameSkipCtx)); if (pChObj->trickPlayObj.skipFrame == TRUE) { /* Skip the output frame */ outFrameSkipList.frames[outFrameSkipList.numFrames] = pReqObj->OutFrameList.frames[j]; outFrameSkipList.numFrames++; } else { outFrameList.frames[outFrameList.numFrames] = pReqObj->OutFrameList.frames[j]; outFrameList.numFrames++; } } } //归还队列; status = Utils_quePut(&pObj->reqQue, pReqObj, BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); pObj->reqQueCount--; } if (outFrameList.numFrames) { //解码后的数据,压入到队列,供下一个link使用 status = Utils_bufPutFullExt(&pObj->outObj.bufOutQue, &outFrameList); UTILS_assert(status == FVID2_SOK); sendCmd = TRUE; } if (outFrameSkipList.numFrames) { status = DecLink_codecFreeProcessedFrames(pObj, &outFrameSkipList); UTILS_assert(status == DEC_LINK_S_SUCCESS); } if (inBufList.numBufs) { /* Free input frames */ pInQueParams = &pObj->createArgs.inQueParams; System_putLinksEmptyBufs(pInQueParams->prevLinkId, pInQueParams->prevLinkQueId, &inBufList); pObj->inBufPutCount += inBufList.numBufs; } /* Send-out the output bitbuffer */ if (sendCmd == TRUE) { //往下一个link发送消息,告诉下一个link数据已经准备好了 System_sendLinkCmd(pObj->createArgs.outQueParams.nextLink, SYSTEM_CMD_NEW_DATA); } return FVID2_SOK; } 4.11)Utils_bufPutFullExt 就是将buff压入到输出full队列,然后提供api供外部的其他link使用; Int32 Utils_bufPutFullExt(Utils_BufHndlExt * pHndl, FVID2_FrameList * pFrameList) { UInt32 idx; Int32 status; UTILS_assert(pHndl != NULL); UTILS_assert(pFrameList != NULL); UTILS_assert(pFrameList->numFrames <= FVID2_MAX_FVID_FRAME_PTR); for (idx = 0; idx < pFrameList->numFrames; idx++) { status = Utils_quePut(&pHndl->fullQue, pFrameList->frames[idx], BIOS_NO_WAIT); UTILS_assert(status == FVID2_SOK); } return FVID2_SOK; } 4.12)DecLink_getFullFrames 函数提供外部调用,获取解码后的帧数据; Int32 DecLink_getFullFrames(Utils_TskHndl * pTsk, UInt16 queId, FVID2_FrameList * pFrameList) { DecLink_Obj *pObj = (DecLink_Obj *) pTsk->appData; UTILS_assert(queId < DEC_LINK_MAX_OUT_QUE); return Utils_bufGetFullExt(&pObj->outObj.bufOutQue, pFrameList, BIOS_NO_WAIT); } 在解码器初始化函数已经注册了该回调函数 linkObj.linkGetFullFrames = DecLink_getFullFrames; 在下一个link调用preLink的该函数获取解码后的数据; 5)IpcFrameOutM3 5.1)IpcFramesOutLink_tskMain函数中调用 IpcFramesOutLink_processFrameBufs获取解码后的数据; Void IpcFramesOutLink_tskMain(struct Utils_TskHndl * pTsk, Utils_MsgHndl * pMsg) { UInt32 cmd = Utils_msgGetCmd(pMsg); Bool ackMsg, done; Int32 status; IpcFramesOutLink_Obj *pObj = (IpcFramesOutLink_Obj *) pTsk->appData; if (cmd != SYSTEM_CMD_CREATE) { Utils_tskAckOrFreeMsg(pMsg, FVID2_EFAIL); return; } status = IpcFramesOutLink_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; case SYSTEM_CMD_NEW_DATA: Utils_tskAckOrFreeMsg(pMsg, status); IpcFramesOutLink_processFrameBufs(pObj); IpcFramesOutLink_releaseFrameBufs(pObj); break; case IPCFRAMESOUTRTOS_LINK_CMD_SET_FRAME_RATE: { IpcOutM3Link_ChFpsParams *params; params = (IpcOutM3Link_ChFpsParams *) Utils_msgGetPrm(pMsg); IpcFramesOutLink_SetFrameRate(pObj, params); Utils_tskAckOrFreeMsg(pMsg, status); } break; case IPCFRAMESOUTRTOS_LINK_CMD_PRINT_STATISTICS: IpcFramesOutLink_printStatistics(pObj, TRUE); Utils_tskAckOrFreeMsg(pMsg, status); break; case SYSTEM_IPC_CMD_RELEASE_FRAMES: Utils_tskAckOrFreeMsg(pMsg, status); #ifdef SYSTEM_DEBUG_IPC_RT Vps_printf(" %d: IPC_FRAMES_OUT : Received Notify !!!\n", Utils_getCurTimeInMsec()); #endif IpcFramesOutLink_releaseFrameBufs(pObj); break; default: Utils_tskAckOrFreeMsg(pMsg, status); break; } } IpcFramesOutLink_delete(pObj); #ifdef SYSTEM_DEBUG_IPC_FRAMES_OUT Vps_printf(" %d: IPC_FRAMES_OUT : Delete Done !!!\n", Utils_getCurTimeInMsec()); #endif if (ackMsg && pMsg != NULL) Utils_tskAckOrFreeMsg(pMsg, status); return; } 5.2)IpcFramesOutLink_processFrameBufs获取数据; Int32 IpcFramesOutLink_processFrameBufs(IpcFramesOutLink_Obj * pObj) { System_LinkInQueParams *pInQueParams; FVID2_FrameList bufList; FVID2_Frame *pFrameBuf = NULL; SystemIpcFrames_ListElem *pListElem; Int32 status; Int32 bufId; UInt32 curTime; FVID2_FrameList freeFrameBufList; UInt8 queId; UInt32 sendMsgToTsk = 0; UInt32 chPerQueue; IpcFramesOutLink_ChObj *pChObj; pInQueParams = &pObj->createArgs.baseCreateParams.inQueParams; bufList.numFrames = 0; //下面函数是从解码link获取数据,数据保存在bufList中; System_getLinksFullFrames(pInQueParams->prevLinkId, pInQueParams->prevLinkQueId, &bufList); freeFrameBufList.numFrames = 0; curTime = Utils_getCurTimeInMsec(); if (bufList.numFrames) { #ifdef SYSTEM_DEBUG_IPC_RT Vps_printf(" %d: IPC_FRAMES_OUT : Received %d framebufs !!!\n", Utils_getCurTimeInMsec(), bufList.numFrames); #endif UTILS_assert(bufList.numFrames <= FVID2_MAX_FVID_FRAME_PTR); pObj->stats.recvCount += bufList.numFrames; sendMsgToTsk = 0; chPerQueue = (pObj->numCh / pObj->createArgs.baseCreateParams.numOutQue); #ifdef IPC_FRAMES_IN_ENABLE_PROFILE Utils_prfTsBegin(pObj->stats.tsHandle); #endif /* IPC_FRAMES_IN_ENABLE_PROFILE */ pObj->totalFrameCount += bufList.numFrames; for (bufId = 0; bufId < bufList.numFrames; bufId++) { Bool doFrameDrop; pFrameBuf = bufList.frames[bufId]; UTILS_assert(pFrameBuf != NULL); pChObj = &pObj->chObj[pFrameBuf->channelNum]; pChObj->inFrameRecvCount++; doFrameDrop = Utils_doSkipFrame(&(pChObj->frameSkipCtx)); /* frame skipped due to user setting */ if(doFrameDrop) { pChObj->inFrameUserSkipCount++; UTILS_assert(freeFrameBufList.numFrames < FVID2_MAX_FVID_FRAME_PTR); freeFrameBufList.frames[freeFrameBufList.numFrames] = pFrameBuf; freeFrameBufList.numFrames++; pObj->stats.droppedCount++; continue; } queId = (pFrameBuf->channelNum / chPerQueue); //从队列中取一个buff,赋值给pListElem status = Utils_queGet(&pObj->listElemQue, (Ptr *) & pListElem, 1, BIOS_NO_WAIT); UTILS_assert(!UTILS_ISERROR(status)); if (status != FVID2_SOK) { /* normally this condition should not happen, if it happens * return the framebuf back to its generator */ #if 0 Vps_printf(" IPC_OUT: Dropping framebuf\n"); #endif UTILS_assert(freeFrameBufList.numFrames < FVID2_MAX_FVID_FRAME_PTR); freeFrameBufList.frames[freeFrameBufList.numFrames] = pFrameBuf; freeFrameBufList.numFrames++; pObj->stats.droppedCount++; pChObj->inFrameUserSkipCount++; continue; } UTILS_assert(SYSTEM_IPC_FRAMES_GET_BUFSTATE(pListElem->bufState) == IPC_FRAMEBUF_STATE_FREE); UTILS_assert(SYSTEM_IPC_FRAMES_GET_BUFOWNERPROCID(pListElem->bufState) == System_getSelfProcId()); SYSTEM_IPC_FRAMES_SET_BUFSTATE(pListElem->bufState, IPC_FRAMEBUF_STATE_ALLOCED); IpcFramesOutLink_copyFrameBufInfo2ListElem(pObj, pListElem, pFrameBuf); pFrameBuf->timeStamp = curTime; SYSTEM_IPC_FRAMES_SET_BUFSTATE(pListElem->bufState, IPC_FRAMEBUF_STATE_OUTQUE); sendMsgToTsk |= (1 << queId); //压入到ListMP,提供给IpcFrameInLink(A8)调用; status = ListMP_putTail(pObj->listMPOutHndl, (ListMP_Elem *) pListElem); UTILS_assert(status == ListMP_S_SUCCESS); pChObj->inFrameProcessCount++; } #ifdef IPC_FRAMES_IN_ENABLE_PROFILE Utils_prfTsEnd(pObj->stats.tsHandle, bufList.numFrames); #endif /* IPC_FRAMES_IN_ENABLE_PROFILE */ if (freeFrameBufList.numFrames) { System_putLinksEmptyFrames(pInQueParams->prevLinkId, pInQueParams->prevLinkQueId, &freeFrameBufList); } /* ProcessLink enable, send the notification to processLink else send to next Link */ //发送通知; if (pObj->createArgs.baseCreateParams.processLink != SYSTEM_LINK_ID_INVALID) { if (pObj->createArgs.baseCreateParams.notifyProcessLink) { System_ipcSendNotify(pObj->createArgs.baseCreateParams.processLink); } } else { for (queId = 0; queId < pObj->createArgs.baseCreateParams.numOutQue; queId++) { if ((pObj->createArgs.baseCreateParams.notifyNextLink) && (sendMsgToTsk & 0x1)) { System_ipcSendNotify(pObj->createArgs.baseCreateParams.outQueParams[queId]. nextLink); } sendMsgToTsk >>= 1; if (sendMsgToTsk == 0) break; } } if (pObj->createArgs.baseCreateParams.noNotifyMode) { if (FALSE == pObj->prd.clkStarted) { IpcFramesOutLink_startPrdObj(pObj, IPC_FRAMESOUT_LINK_DONE_PERIOD_MS, FALSE); } } } return FVID2_SOK; } 7)IpcFrameInHost(A8) A8如何获取到数据; 7.1)IpcFramesInLink_tskMain 函数 static Int IpcFramesInLink_tskMain(struct OSA_TskHndl * pTsk, OSA_MsgHndl * pMsg, Uint32 curState) { UInt32 cmd = OSA_msgGetCmd(pMsg); Bool ackMsg, done; Int status = IPC_FRAMES_IN_LINK_S_SUCCESS; IpcFramesInLink_Obj *pObj = (IpcFramesInLink_Obj *) pTsk->appData; OSA_printf("%s:Entered", __func__); if (cmd != SYSTEM_CMD_CREATE) { OSA_tskAckOrFreeMsg(pMsg, OSA_EFAIL); return status; } status = IpcFramesInLink_create(pObj, OSA_msgGetPrm(pMsg)); OSA_tskAckOrFreeMsg(pMsg, status); if (status != OSA_SOK) return status; done = FALSE; ackMsg = FALSE; while (!done) { status = OSA_tskWaitMsg(pTsk, &pMsg); if (status != OSA_SOK) break; cmd = OSA_msgGetCmd(pMsg); switch (cmd) { case SYSTEM_CMD_DELETE: done = TRUE; ackMsg = TRUE; break; case SYSTEM_CMD_NEW_DATA: OSA_tskAckOrFreeMsg(pMsg, status); //OSA_assert(pObj->prd.numPendingCmd > 0); OSA_mutexLock(&pObj->prd.mutexPendingCmd); pObj->prd.numPendingCmd--; OSA_mutexUnlock(&pObj->prd.mutexPendingCmd); //从ipcOutLink中获取数据 IpcFramesInLink_processFrameBufs(pObj); break; case SYSTEM_CMD_STOP: IpcFramesInLink_stop(pObj); OSA_tskAckOrFreeMsg(pMsg, status); break; default: OSA_tskAckOrFreeMsg(pMsg, status); break; } } IpcFramesInLink_delete(pObj); #ifdef SYSTEM_DEBUG_IPC_FRAMES_IN OSA_printf(" %d: IPC_FRAMES_IN : Delete Done !!!\n", OSA_getCurTimeInMsec()); #endif if (ackMsg && pMsg != NULL) OSA_tskAckOrFreeMsg(pMsg, status); return IPC_FRAMES_IN_LINK_S_SUCCESS; } 7.2)IpcFramesInLink_processFrameBufs 调用ListMP_getHead获取listElem,然后 static Int32 IpcFramesInLink_processFrameBufs(IpcFramesInLink_Obj * pObj) { VIDFrame_Buf *pFrameBuf; SystemIpcFrames_ListElem *pListElem; UInt32 numFrameBufs; Int32 status; UInt32 curTime; numFrameBufs = 0; curTime = OSA_getCurTimeInMsec(); while (1) { pListElem = ListMP_getHead(pObj->listMPOutHndl); if (pListElem == NULL) break; IpcFramesInLink_getFrameBuf(pObj, pListElem, &pFrameBuf); OSA_assert(SYSTEM_IPC_FRAMES_GET_BUFSTATE(pListElem->bufState) == IPC_FRAMEBUF_STATE_OUTQUE); pListElem->timeStamp = curTime; pListElem->frameBuf.linkPrivate = (Ptr)pListElem; SYSTEM_IPC_FRAMES_SET_BUFOWNERPROCID(pListElem->bufState); SYSTEM_IPC_FRAMES_SET_BUFSTATE(pListElem->bufState, IPC_FRAMEBUF_STATE_DEQUEUED); pObj->stats.recvCount++; //压入队列 status = OSA_quePut(&pObj->outFrameBufQue, (Int32)pFrameBuf, OSA_TIMEOUT_NONE); OSA_assert(status == OSA_SOK); numFrameBufs++; } #ifdef SYSTEM_DEBUG_IPC_RT OSA_printf(" %d: IPC_FRAMES_IN : Recevived %d framebufs !!!\n", OSA_getCurTimeInMsec(), numFrameBufs); #endif if (numFrameBufs) { if (pObj->createArgs.cbFxn) { pObj->createArgs.cbFxn(pObj->createArgs.cbCtx); } } return IPC_FRAMES_IN_LINK_S_SUCCESS; } 7.3)IpcFramesInLink_getFullFrames提供给外部api使用(IpcFramesInLink_getFullVideoFrames函数) static Int32 IpcFramesInLink_getFullFrames(IpcFramesInLink_Obj * pObj, VIDFrame_BufList * pFrameBufList) { UInt32 idx; Int32 status; VIDFrame_Buf *pFrame; for (idx = 0; idx < VIDFRAME_MAX_FRAME_BUFS; idx++) { status = OSA_queGet(&pObj->outFrameBufQue, (Int32 *) & pFrame, OSA_TIMEOUT_NONE); if (status != OSA_SOK) break; pFrameBufList->frames[idx] = *pFrame; } pFrameBufList->numFrames = idx; return IPC_FRAMES_IN_LINK_S_SUCCESS; }