dm8148 videoM3 link源码解析

例子:从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;
}
时间: 2024-10-19 09:21:20

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

ChrisRenke/DrawerArrowDrawable源码解析

转载请注明出处http://blog.csdn.net/crazy__chen/article/details/46334843 源码下载地址http://download.csdn.net/detail/kangaroo835127729/8765757 这次解析的控件DrawerArrowDrawable是一款侧拉抽屉效果的控件,在很多应用上我们都可以看到(例如知乎),控件的github地址为https://github.com/ChrisRenke/DrawerArrowDrawable

String源码解析(一)

本篇文章内的方法介绍,在方法的上面的注释讲解的很清楚,这里只阐述一些要点. Java中的String类的定义如下: 1 public final class String 2 implements java.io.Serializable, Comparable<String>, CharSequence { ...} 可以看到,String是final的,而且继承了Serializable.Comparable和CharSequence接口. 正是因为这个特性,字符串对象可以被共享,例如下面

Handler机制(四)---Handler源码解析

Handler的主要用途有两个:(1).在将来的某个时刻执行消息或一个runnable,(2)把消息发送到消息队列. 主要依靠post(Runnable).postAtTime(Runnable, long).postDelayed(Runnable, long).sendEmptyMessage(int).sendMessage(Message).sendMessageAtTime(Message).sendMessageDelayed(Message, long)这些方法来来完成消息调度.p

源码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?

问题 在慢慢熟悉android 的过程中,发现一个view 或者layout的初始化,或者构造的流程还是比较清楚的,也就是加到父控件中,然后就开始了对应的生命周期.但是整个界面的父控件,或者说系统的第一个view, 是怎么来的,如何初始化和绘制的呢? 概述 概述:带着困扰我的问题,在前文的基础上,继续分析应用界面和framework的关系,通过分析viewrootimpl 的来源,并结合dialog, popupwindow, 和activity 的 根view的创建流程,回答了问题界面的根vi

Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例

java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例 概要  和学习ArrayList一样,接下来呢,我们先对LinkedList有个整体认识,然后再学习它的源码:最后再通过实例来学会使用LinkedList.内容包括:第1部分 LinkedList介绍第2部分 LinkedList数

【转】Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeMap.内容包括:第1部分 TreeMap介绍第2部分 TreeMap数据结构第3部分 TreeMap源码解析(基于JDK1.6.0_45)第4部分 TreeMap遍历方式第5部分 TreeMap示例 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3310928 第1部

Spring IoC源码解析——Bean的创建和初始化

Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和AOP的容器框架,主要是针对JavaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,MyBatis框架等组合使用. IoC介绍 IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控

Android EventBus3.0使用及源码解析

叨了个叨 最近因为换工作的一些琐事搞的我一个头两个大,也没怎么去学新东西,实在是有些愧疚.新项目用到了EventBus3.0,原来只是听说EventBus的鼎鼎大名,一直没仔细研究过.趁着周末有些时间,研究下代码,也算没有虚度光阴. EventBus GitHub : https://github.com/greenrobot/EventBus EventBus3.0简介 EventBus是greenrobot出品的一个用于Android中事件发布/订阅的库.以前传递对象可能通过接口.广播.文件

给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析

LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明. 1.链表的概念 链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表,下面简单就这四种链表进行图解说明.           1.1.单向链表 单向链表就是通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null.      1. 2.单向循环链表           单向循环