This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

请问DVR RDK中displayLink的callback函数是怎么被调用起来的?

是周期性调用吗? 具体代码在哪? 谢谢!
  • 你好;

           你这里指的回调函数,具体是说的什么地方的程序?

           你是指dispaly link 的运行的源码吗?

           dvr_rdk/mcfw/src_bios6/links_m3vpss/display 

           是这样代码吗?

           

  • 你好,

    应该是通过显示的Vsync。请参考HDVPSS驱动。

    typedef struct
    {
        UInt32                  memType;
        /**< VPDMA Memory type. For valid values see #Vps_VpdmaMemoryType. */
        UInt32                  periodicCallbackEnable;
        /**< TRUE: User callback passed during FVID2 create is called periodically.
             For progressive display, this interval is equal to VSYNC interval.
             For interlaced display, this interval is equal to twice the VSYNC
             interval as frames (two fields) are queued to the driver.
             FALSE: User callback passed during FVID2 create is called only
             if one or more frames (requests) are available in the driver output
             queue for the application to dequeue. */
    } Vps_DispCreateParams;。

  • 是的,谢谢!

    如下代码说明:

    /* Create capture driver */
    Int32 CaptureLink_drvCreateInst(CaptureLink_Obj * pObj, UInt16 instId)
    {

        ...

       pVipCreateArgs->periodicCallbackEnable = TRUE;

       ...

    }

    但是我在《HDVPSS_UserGuide》手册中没有找到Vsync相关说明。

    而且还是不能完全明白displayLink的数据接收处理机制,还请进一步指导:

    (1) displayLink的前一个Link(m3vpssInLink)通过下面的代码给displayLink发送“SYSTEM_CMD_NEW_DATA”消息指示:

               System_sendLinkCmd(pObj->createArgs.baseCreateParams.outQueParams[i].nextLink, SYSTEM_CMD_NEW_DATA);

              但是为何displayLink内没有“SYSTEM_CMD_NEW_DATA”对应处理?

              而是对“ DISPLAY_LINK_CMD_DO_DEQUE”消息的处理:

              Int32 DisplayLink_tskRun(DisplayLink_Obj * pObj, Utils_TskHndl * pTsk,
                             Utils_MsgHndl ** pMsg, Bool * done, Bool * ackMsg)
             {

                       ...

                        case DISPLAY_LINK_CMD_DO_DEQUE:
                                 status = DisplayLink_drvProcessData(pObj);

                        ...

               }

              “ DISPLAY_LINK_CMD_DO_DEQUE”消息是由下面的回调函数发出的:

               Int32 DisplayLink_drvFvidCb(FVID2_Handle handle, Ptr appData, Ptr reserved)
               {
                   ...
                   Utils_tskSendCmd(&pObj->tsk, DISPLAY_LINK_CMD_DO_DEQUE);

                   ...

              }

    (2) displayLink通过下面三种情况获取帧数据,不是很理解,请帮忙解释一下三种情况:         

    Int32 DisplayLink_drvProcessData(DisplayLink_Obj * pObj)
    {
        FVID2_FrameList frameList;
        FVID2_FrameList freeFrameList;
        FVID2_FrameList displayFrameList;
        UInt32 freeFrameNum, elaspedTime;
        System_LinkInQueParams *pInQueParams;
        FVID2_Frame *pFrame;
        Int32 status;
        UInt32 latency;
        Int i;
        UInt32 frameIdx;

        elaspedTime = Utils_getCurTimeInMsec() - pObj->startTime;

        if ((elaspedTime - pObj->prevTime) > 24 * 60 * 60 * 1000)
        {
            DisplayLink_drvPrintRtStatus(pObj, elaspedTime);

            pObj->prevTime = elaspedTime;
        }

        if(pObj->displayInstId==0)
        {
            System_displayUnderflowCheck(FALSE);
        }

        do
        {
            UInt32 freeQueueId;
           //*情况一:*/ /* dequeue all completed frames *
            status = DisplayLink_drvDeQueue(pObj,&freeFrameList,
                                            &freeQueueId);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : drvDeQueue Frames %d  !!!\n",
        Utils_getCurTimeInMsec(), freeFrameList.numFrames);
    #endif
            if (freeFrameList.numFrames)
            {
                pObj->inFramePutCount += freeFrameList.numFrames;

                UTILS_assert(freeQueueId <
                             pObj->createArgs.numInputQueues);
                pInQueParams = &pObj->createArgs.inQueParams[freeQueueId];
                System_putLinksEmptyFrames(pInQueParams->prevLinkId,
                                           pInQueParams->prevLinkQueId, &freeFrameList);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : 1st putLinksEmptyFrames %d  !!!\n",
        Utils_getCurTimeInMsec(), freeFrameList.numFrames);
    #endif
            }

        } while (status == FVID2_SOK);

    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : numInputQueues = %d , curActiveQueue =  %d !!!\n",
        Utils_getCurTimeInMsec(), pObj->createArgs.numInputQueues,pObj->curActiveQueue);
    #endif

        /*情况二:*//* Free frames queued in inactive queues immediately */
        for (i = 0; i < pObj->createArgs.numInputQueues;i++)
        {
            if (i != pObj->curActiveQueue)
            {
                frameList.numFrames = 0;
                pInQueParams =
                  &pObj->createArgs.inQueParams[i];           
                System_getLinksFullFrames(pInQueParams->prevLinkId,
                                          pInQueParams->prevLinkQueId,
                                          &frameList);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : 1st getLinksFullFrames %d  !!!\n",
        Utils_getCurTimeInMsec(), frameList.numFrames);
    #endif
                if (frameList.numFrames)
                {
                    pObj->inFrameGetCount += frameList.numFrames;
                    pObj->inFramePutCount += frameList.numFrames;
                    System_putLinksEmptyFrames(pInQueParams->prevLinkId,
                                               pInQueParams->prevLinkQueId,
                                               &frameList);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : 2nd putLinksEmptyFrames %d  !!!\n",
        Utils_getCurTimeInMsec(), freeFrameList.numFrames);
    #endif
                }
            }
        }
        UTILS_assert(pObj->curActiveQueue < pObj->createArgs.numInputQueues);
        pInQueParams = &pObj->createArgs.inQueParams[pObj->curActiveQueue];
        
       /*情况三:*/ /* que frames if any */
        System_getLinksFullFrames(pInQueParams->prevLinkId,
                                  pInQueParams->prevLinkQueId, &frameList);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : 2st getLinksFullFrames %d  !!!\n",
        Utils_getCurTimeInMsec(), frameList.numFrames);
    #endif
        pObj->inFrameGetCount += frameList.numFrames;

        freeFrameNum = 0;
        DisplayLink_drvLock(pObj);
        frameIdx = 0;
        while((pObj->maxQueueCount)
              &&
              (frameIdx < frameList.numFrames))
        {
            pFrame = frameList.frames[frameIdx];
            frameIdx++;
            UTILS_assert(pFrame != NULL);
            if (pFrame->channelNum == pObj->curDisplayChannelNum)
            {
                Bool frameReject;
                UInt32 pitch0,pitch1;

                pitch0 = pObj->displayFormat.pitch[0];
                pitch1 = pObj->displayFormat.pitch[1];
                if (DisplayLink_drvDoInputPitchDoubling(pObj))
                {
                    pitch0 /= 2;
                    pitch1 /= 2;
                }

                UTILS_assert(DISPLAY_LINK_BLANK_FRAME_CHANNEL_NUM !=
                             pFrame->channelNum);
                pFrame->addr[1][0] =
                    (UInt8 *) pFrame->addr[0][0] + pitch0;
                pFrame->addr[1][1] =
                    (UInt8 *) pFrame->addr[0][1] + pitch1;
    #ifdef SYSTEM_DEBUG_DISPLAY_RT
                Vps_printf(" %d: DISPLAY: Queue %d frames\n", Utils_getCurTimeInMsec(),
                           displayFrameList.numFrames);
    #endif
                latency = Utils_getCurTimeInMsec() - pFrame->timeStamp;

                if(latency>pObj->maxLatency)
                    pObj->maxLatency = latency;
                if(latency<pObj->minLatency)
                    pObj->minLatency = latency;
                /* queue frame for display */
                displayFrameList.numFrames = 0;
                DisplayLink_drvSetFrameInfo(pObj,
                                            &pFrame,
                                            &frameReject);
                if (pFrame)
                {
                    if (frameReject)
                    {
                        UTILS_assert(freeFrameNum <
                                     UTILS_ARRAYSIZE(freeFrameList.frames));
                        /* error in queing to display, instead of asserting
                            release the frame and continue
                        */
                        freeFrameList.frames[freeFrameNum] = pFrame;
                        freeFrameNum++;
                    }
                    else
                    {
                        displayFrameList.frames[displayFrameList.numFrames] = pFrame;
                        displayFrameList.numFrames++;
                        displayFrameList.perListCfg = NULL;
                        DisplayLink_drvHandleDynamicPitchChange(pObj,&displayFrameList);
                        DisplayLink_validateFrameList(pObj,
                                                      &displayFrameList);
                        pObj->queueCount += displayFrameList.numFrames;
                        pObj->numBufsInDriver++;

                        status = FVID2_queue(pObj->displayHndl,
                                             &displayFrameList,
                                             0);
                        pObj->maxQueueCount--;

                        if(status!=FVID2_SOK)
                        {

                             Vps_rprintf(" %d: DISPLAY (%d): Queue to driver failed !!!\n", Utils_getCurTimeInMsec(),
                                   pObj->tskId);

                            UTILS_assert(freeFrameNum <
                                         UTILS_ARRAYSIZE(freeFrameList.frames));
                            /* error in queing to display, instead of asserting
                                release the frame and continue
                            */
                            freeFrameList.frames[freeFrameNum] = pFrame;
                            freeFrameNum++;
                            DisplayLink_drvFreeFrameInfo(pObj,
                                                         &displayFrameList);
                        }
                    }
               }
            }
            else
            {
                UTILS_assert(freeFrameNum <
                             UTILS_ARRAYSIZE(freeFrameList.frames));
                freeFrameList.frames[freeFrameNum] = pFrame;
                freeFrameNum++;
            }
        }
        DisplayLink_drvUnlock(pObj);

        for (i = frameIdx; i < frameList.numFrames;i++)
        {
            UTILS_assert(freeFrameNum < UTILS_ARRAYSIZE(freeFrameList.frames));
            freeFrameList.frames[freeFrameNum] = frameList.frames[i];
            freeFrameNum++;
        }
        if (freeFrameNum)
        {
            freeFrameList.numFrames = freeFrameNum;
            pObj->inFramePutCount += freeFrameList.numFrames;

            System_putLinksEmptyFrames(pInQueParams->prevLinkId,
                                       pInQueParams->prevLinkQueId, &freeFrameList);
    #ifdef SYSTEM_DEBUG_FLOW     
        Vps_printf(" %d: DisplayLink_drvProcessData   : 3rd putLinksEmptyFrames %d  !!!\n",
        Utils_getCurTimeInMsec(), freeFrameList.numFrames);
    #endif
        }

        return FVID2_SOK;
    }

    (3)我们现在遇到的问题如下(经打印的Log分析显示),请帮忙分析原因:

    (3.1) displayLink的前一个Link(m3vpssInLink)通过下面的代码给displayLink发送“SYSTEM_CMD_NEW_DATA”消息指示,发送了19个帧(19次,每次一个帧)数据;

    (3.2) displayLink仅在上述:

                     /*情况一:*/    获取5帧数据,有release framebuffer操作;

                     /*情况三:*/    获取7帧数据,没有release framebuffer操作(要继续查原因);

    (3.3) 后续m3vpssInLink不再接收到frame数据,c6xdsp在 ListMP_getHead(pObj->listMPInHndl)后来总是返回NULL后挂死:        

    Int32 IpcFramesOutLink_releaseFrameBufs(IpcFramesOutLink_Obj * pObj)
    {
        System_LinkInQueParams *pInQueParams;
        SystemIpcFrames_ListElem *pListElem = NULL;
        Int32 status;
        UInt32 curTime, roundTripTime;
        FVID2_Frame *pFrameBuf = NULL;
        FVID2_FrameList freeFrameBufList;
        UInt8 queId;
        UInt32 chPerQueue;
        UInt32 times = 0;

        pInQueParams = &pObj->createArgs.baseCreateParams.inQueParams;

        do
        {
            freeFrameBufList.numFrames = 0;

            curTime = Utils_getCurTimeInMsec();
            while (freeFrameBufList.numFrames < FVID2_MAX_FVID_FRAME_PTR)
            {
                pListElem = ListMP_getHead(pObj->listMPInHndl);
                if (pListElem == NULL)
                    break;
                UTILS_assert(SYSTEM_IPC_FRAMES_GET_BUFSTATE(pListElem->bufState)
                             == IPC_FRAMEBUF_STATE_INQUE);
                IpcFramesOutLink_mapListElem2FrameBuf(pObj, pListElem, &pFrameBuf);
                UTILS_assert(pFrameBuf != NULL);
                if (curTime > pFrameBuf->timeStamp)
                {
                    roundTripTime = curTime - pFrameBuf->timeStamp;
                    pObj->stats.totalRoundTrip += roundTripTime;
                }
                /* Restore the original timestamp as it may be used by next link */
                pFrameBuf->timeStamp = pListElem->frameBuf.timeStamp;
                freeFrameBufList.frames[freeFrameBufList.numFrames] = pFrameBuf;
                freeFrameBufList.numFrames++;
                UTILS_assert(freeFrameBufList.numFrames <=
                             FVID2_MAX_FVID_FRAME_PTR);
                /* release ListElem back to queue */
                SYSTEM_IPC_FRAMES_SET_BUFOWNERPROCID(pListElem->bufState);
                SYSTEM_IPC_FRAMES_SET_BUFSTATE(pListElem->bufState,
                                             IPC_FRAMEBUF_STATE_FREE);
                status = Utils_quePut(&pObj->listElemQue, pListElem, BIOS_NO_WAIT);
                UTILS_assert(status == FVID2_SOK);
            }

    #ifdef SYSTEM_DEBUG_IPC_RT
            Vps_printf(" %d: IPC_FRAMES_OUT   : Releasing %d framebufs !!!\n",
                       Utils_getCurTimeInMsec(), freeFrameBufList.numFrames);
    #endif

            if (freeFrameBufList.numFrames)
            {

                /* If the buffer is released via processing link, pass it to next link */
                /* NextLink will take care to release the buffer to privLink */
                if(pObj->createArgs.baseCreateParams.processLink != SYSTEM_LINK_ID_INVALID)
                {
                    Int i;
                    UInt32 sendMsgToTsk = 0;

                    for (i = 0; i < freeFrameBufList.numFrames;i++)
                    {
                        pObj->stats.forwardCount++;

                        /** Split the frames into both the output queues,
                        * if they are enabled. Else use output queue 0 only.
                        * Also, if output queue 1 is used, frames sent to this queue
                        * should be modified before submitting so that the
                        * pFrame->channelNum should start with 0 and not with
                        * (pObj->nsfCreateParams.numCh / 2).
                        */
                        pFrameBuf = freeFrameBufList.frames[i];

                        chPerQueue =
                            (pObj->numCh / pObj->createArgs.baseCreateParams.numOutQue);
                        queId = (pFrameBuf->channelNum / chPerQueue);
                        pFrameBuf->channelNum = pFrameBuf->channelNum % chPerQueue;

                        status =  Utils_quePut(&pObj->outFrameBufQue[queId],
                                               freeFrameBufList.frames[i],
                                               BIOS_NO_WAIT);
                        UTILS_assert(!UTILS_ISERROR(status));
                        sendMsgToTsk |= (1 << queId);
                    }
                    if (pObj->createArgs.baseCreateParams.notifyNextLink)
                    {
                        for (i = 0; i < pObj->createArgs.baseCreateParams.numOutQue;i++)
                        {
                            if (sendMsgToTsk & 0x1)
                            {
                                System_sendLinkCmd(pObj->createArgs.baseCreateParams.outQueParams[i].
                                    nextLink, SYSTEM_CMD_NEW_DATA);
                            }
                            sendMsgToTsk >>= 1;
                            if (sendMsgToTsk == 0)
                                break;
                        }
                    }
                }
                else
                {
                    System_putLinksEmptyFrames(pInQueParams->prevLinkId,
                                               pInQueParams->prevLinkQueId,
                                               &freeFrameBufList);
                }
            }
        } while (pListElem != NULL);

        return FVID2_SOK;
    }

  • 你好,

    显示模块是周期性显示数据的,不需要前面一个link一发送数据,就去显示。所以显示link只需要在需要显示的时候去看有没有新数据,如果有就显示新数据,如果没有,就显示之前的数据。

    下面的论坛讨论有如下描述:

    https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/717/p/210164/743682#743682

    if the driver does not have any more buffers for the display, it keeps displaying last buffer and since it is displaying the buffer, it retains the last buffer.

    In call cases frames are displayed at Vsync intervals. At every vsync display driver checks for new frames and if new frames are present it releases old frame.So if new frame is queued old frame is released at next Vsync after the frame is queued.

    There two, queue and buffer update, are different operations, application call queue from the task context and driver updates the buffer in the isr context, so it does not update the buffer immediately after buffer is queued. All the buffer including the last buffer will get displayed at the display frame rates, how many times last buffer gets displayed depends on the applicaiton delay in queueing the buffer.

    显示的驱动是比较复杂的,如果你再看看hdvpss驱动,里面还有一个DLM(dispaly list manager)。如果去掉DSP link显示就没有问题,那我认为还是应该看看其他link。

  • good idea! 我把dspAlgLink “bypass”掉看看情况.
  • 仔细对照Log分析了displayLink代码,认为displayLink处理数据流是这样的: 1. displayLink调用前一个link(m3vpssInLink)的GetFullFrameBufs()获取发送过来的帧数据buffer; 2. displayLink调用Frame_que()将获取的帧数据buffer再交给displayLink驱动; 3. displayLink调用Frame_deque() 获取 displayLink驱动返回的数据buffer,再将此buffer释放给前一个Link; 我们的问题还是上面第1步获取的帧数据较前一个Link发送的少很多,导致前一个Link后来再也获取不到displayLink释放的buffer而挂死. 还请大家指导!
  • 我把dspAlgLink “bypass”掉,图像是正常、稳定显示的. 还是dspAlgLink代码有问题!
  • hi,chris 问题已定位. 是由于displayLink内QUE和DEQUE次数不一致导致. 如果前一个Link QUE的是无效帧数据,displayLink不公正常Deque回来. 确保帧数据有效,问题解决. 但即使QUE了无效数据,displayLink按理也该Deque回帧buffer. 这个问题还不知原因.