样例:从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;
}

dm8148 videoM3 link源代码解析的更多相关文章

  1. Android源代码解析之(六)--&gt;Log日志

    转载请标明出处:一片枫叶的专栏 首先说点题外话,对于想学android framework源代码的同学,事实上能够在github中fork一份,详细地址:platform_frameworks_bas ...

  2. struts2 文件上传和下载,以及部分源代码解析

    struts2 文件上传 和部分源代码解析,以及一般上传原理 (1) 单文件上传 一.简单介绍 Struts2并未提供自己的请求解析器,也就是就Struts2不会自己去处理multipart/form ...

  3. Android源代码解析之(七)--&gt;LruCache缓存类

    转载请标明出处:一片枫叶的专栏 android开发过程中常常会用到缓存.如今主流的app中图片等资源的缓存策略通常是分两级.一个是内存级别的缓存,一个是磁盘级别的缓存. 作为android系统的维护者 ...

  4. Tomcat请求处理过程(Tomcat源代码解析五)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  5. Spring源代码解析

    Spring源代码解析(一):IOC容器:http://www.iteye.com/topic/86339 Spring源代码解析(二):IoC容器在Web容器中的启动:http://www.itey ...

  6. Arrays.sort源代码解析

    Java Arrays.sort源代码解析 Java Arrays中提供了对所有类型的排序.其中主要分为Primitive(8种基本类型)和Object两大类. 基本类型:采用调优的快速排序: 对象类 ...

  7. Spring源代码解析(收藏)

    Spring源代码解析(收藏)   Spring源代码解析(一):IOC容器:http://www.iteye.com/topic/86339 Spring源代码解析(二):IoC容器在Web容器中的 ...

  8. volley源代码解析(七)--终于目的之Response&lt;T&gt;

    在上篇文章中,我们终于通过网络,获取到了HttpResponse对象 HttpResponse是android包里面的一个类.然后为了更高的扩展性,我们在BasicNetwork类里面看到.Volle ...

  9. Cocos2d-x源代码解析(1)——地图模块(3)

    接上一章<Cocos2d-x源代码解析(1)--地图模块(2)> 通过前面两章的分析,我们能够知道cocos将tmx的信息结构化到 CCTMXMapInfo.CCTMXTilesetInf ...

随机推荐

  1. 【VBA】Do While……Loop循环,遍历某列

    [说明] Do While……Loop循环,遍历某列 i = Do While Trim(T_sh.Cells(i, NOTESID_COL)) <> "" If T_ ...

  2. 【07】 vue 之 Vue-router

    注意: vue-router@2.x 只适用于 Vue 2.x 版本. vue-router@1.x 对应于Vue1.x版本. 的Github地址:vue-router 文档地址 7.2. vue-r ...

  3. practical system design with mef & mef[ trans from arup.codeplex.com/]

    Practical System Design using MEF MVVM RX MOQ Unit Tests in WPF Posted on May 21, 2015 by Arup Baner ...

  4. .net web api ioc unity usage

    1.use nuget to install unity.webapi 2.add configurations in application_start folder using Microsoft ...

  5. duilib入门简明教程 -- 自绘标题栏(5) (转)

    原文转自 http://www.cnblogs.com/Alberl/p/3343667.html         如果大家有做过标题栏的自绘,肯定会感慨各种不容易,并且现有的一些资料虽然完美的实现了 ...

  6. 【Visual Studio - Dependency Walker】查找程序依赖的动态链接库文件(转)

    原文转自 http://163n.blog.163.com/blog/static/5603555220113151113287/ 有时我们需要知道一个程序依赖哪些动态链接库(DLL)文件.实际上,有 ...

  7. 7天学习opengl入门

    http://blog.csdn.net/slience_perseverance/article/details/8096233 10月13号下午3:00队长给我开了一个会,10.14号开始学习op ...

  8. 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---14

    以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:

  9. Python 函数的一般形式及参数

    #!/usr/bin/env python # -*- coding:utf-8 -*- # @Time : 2017/11/01 21:46 # @Author : lijunjiang # @Fi ...

  10. MongoDB的使用[转]

    http://www.cnblogs.com/TankMa/archive/2011/06/08/2074947.html