codec engine代碼閱讀七---codecs中的xDM,XDAIS函數解析

寫可以被CE使用的算法通常要實現XDAIS或xDM標準。xDM是XDAIS的擴展。xDM自己又包括八種接口,按音頻,視頻,圖像,語音每個再分爲編碼器和解碼器。xDM和XDAIS的關係如圖所示。


XDAIS標準分爲兩個接口,一個是IALG和個是IMOD。其框架如圖所示。而xDM則是在XDAIS的基礎上增加了一個接口,其框架圖如圖所示。
首先我們要先了解xDAIS的ialg接口:
ialg接口有七個函數需要我們去實現,這個鏈接是七個函數的調用流程。這七個函數組成一個結構體稱爲ialgfxns.其結構原型爲: 
typedef struct IALG_Fxns {
    Void    *implementationId;
    Void    (*algActivate)(IALG_Handle);
    Int       (*algAlloc)(const IALG_Params *, struct IALG_Fxns **, IALG_MemRec *);
    Int       (*algControl)(IALG_Handle, IALG_Cmd, IALG_Status *);
    Void    (*algDeactivate)(IALG_Handle);
    Int       (*algFree)(IALG_Handle, IALG_MemRec *);
    Int       (*algInit)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
    Void    (*algMoved)(IALG_Handle, const IALG_MemRec *, IALG_Handle, const IALG_Params *);
    Int       (*algNumAlloc)(Void);
} IALG_Fxns;

有些時候其中的一些函數無需實現,但要賦值爲NULL.結構體中只有第一個成員變量比較特殊,不是函數指針而是一個空指針,它的作用是唯一標識模塊的實現,經常需要用到。

剩下定義的函數可以分爲3類:

1.用於創建algAlloc()、初始化AlgInit()和刪除algFree實例對象的函數。

2.算法處理的函數,包括:algActivate()和algDeactivate();

3.用於控制和重定位 實例對象的函數,包括:algControl()和algMoved()。

剩下的一個algNumAlloc()函數可在任何時候調用且值不變,主要是求得算法實例的需要分配的存儲器數目。

按順序逐一解釋一下:

      1.algActivate()。

功能:在數據處理之前,實現臨時存儲器的初始化。參數是算法實例的句柄IALG_Handle handle,通過該句柄識別出算法需要的不同類型的緩衝,並完成相應的初始化。該函數是可選實現的,僅當在數據處理之前需要初始化時才實現,如不實現可置NULL,以下雷同。

       調用的前提:必須在algInit()成功之後才能調用;handle是一個有效的算法句柄;它不能搶佔對象的其它方法;如果算法實現了IDMA2接口,則algActivate()必須在dmaInit()成功後調用。實現此函數之後,算法中所有方法都可使用。

       2.algAlloc()。
功能:得到算法對象對於存儲器的需求情況。

第一個參數是指向用於創建算法對象的參數,如果爲NULL則是默認參數,

第二個參數是輸出參數,返回給父IALG函數;

第三個參數是一個存儲器記錄的表格。如果成功返回一個非0整數,這個整數說明表格中包含多少個有效項。

       調用前提:存儲器表格中記錄的個數不能少於algNmAlloc()返回值,params允許爲空。

       3.algControl()。
功能:算法的控制和狀態信息的提取。

第一個參數是算法實例的句柄,剩下的2個參數是算法特定的。返回值是IALG_EOK或是其它出錯信息。這個函數實現是可選的,如不實現設置爲空。

       調用條件:只能在algInit()後調用,handle是一個有效句柄,cmd的數值必須小於IALG_SYSCMD。

      4.algDeactivate()。
功能:保存所有的持久數據到非臨時存儲器上。與algActivate()類似,在其之後只能調用algActive()或algFree()。

      5.algFree()
功能:獲得算法的存儲器資源。與algAlloc()類似,返回值是存儲器表格的有效項數。存儲器表格中包含所有傳遞給算法的指向緩衝的指針。

6.algInit()。

功能:初始化算法實例對象。

algInit()實現在運行階段創建算法實例對象,在該函數成功返回後,算法實例對象纔開始處理數據。

參數解釋:

第一個參數是算法實例句柄,它指向一個初始化後的IALG_Obj結構,數值與memTab[0].base相同(看不明白先看下他們的數據結構);

第二個參數是存儲器記錄表格,有效記錄項目數與algAlloc()相同;

第三個參數是另一個算法實例對象的句柄,通常爲NULL,表示沒有父對象存在;

最後一個是算法特定參數,可以爲NULL。

     調用條件較複雜。。。。。。

    7. algMoved()。    
功能:重新定位算法實例的存儲器資源。主要是當算法實例需要移動時調用,可選實現,不實現表明不可移動。參數與algInit()中一樣。

    8. algNumAlloc()。
功能:返回需要的存儲器數目。必須大於等於algAlloc()的返回值,可以在任何時刻調用,且值不變

本樓結合videnc_copy和viddec_copy中的代碼詳細介紹一下第一個函數algAlloc()。
2.algAlloc()。

功能:得到算法對象對於存儲器的需求情況。

第一個參數是指向用於創建算法對象的參數,如果爲NULL則是默認參數,

第二個參數是輸出參數,返回給父IALG函數;

第三個參數是一個存儲器記錄的表格。如果成功返回一個非0整數,這個整數說明表格中包含多少個有效項。

       調用前提:存儲器表格中記錄的個數不能少於algNmAlloc()返回值,params允許爲空。
/*
 *  ======== VIDENCCOPY_TI_alloc ========
 */
Int VIDENCCOPY_TI_alloc(const IALG_Params *algParams,
    IALG_Fxns **pf, IALG_MemRec memTab[])
{
    /* Request memory for my object 爲對象申請內存 */
    memTab[0].size = sizeof(VIDENCCOPY_TI_Obj);//設置內存表項的大小。
    memTab[0].alignment = 0;   //設置內存的對齊方式。
    memTab[0].space = IALG_EXTERNAL;//設置請求的內存類型
    memTab[0].attrs = IALG_PERSIST; //設置內存的屬性


    return (1);  //只做了一個表項,返回一。
}


另一個,viddec_copy的內容是一樣的:


/*
 *  ======== VIDDECCOPY_TI_alloc ========
 */
Int VIDDECCOPY_TI_alloc(const IALG_Params *algParams,
    IALG_Fxns **pf, IALG_MemRec memTab[])
{
    if (curTrace.modName == NULL) {   /* initialize GT (tracing) */
        GT_create(&curTrace, GTNAME);
    }


    GT_3trace(curTrace, GT_ENTER, "VIDDECCOPY_TI_alloc(0x%lx, 0x%lx, 0x%lx)\n",
        algParams, pf, memTab);


    /* Request memory for my object */
    memTab[0].size = sizeof(VIDDECCOPY_TI_Obj);
    memTab[0].alignment = 0;
    memTab[0].space = IALG_EXTERNAL;
    memTab[0].attrs = IALG_PERSIST;

    return (1);
}

然後我們還看algcontrol:這個函數在app中的app.c中被調用了,我們可以直接看看是怎麼調用的:
status = VIDDEC_control(dec, XDM_GETSTATUS, &decDynParams, &decStatus);
參數:VIDDEC_Handle dec = VIDDEC_create(ce, decoderName, NULL); 
dec是一個解碼器實例的句柄。
XDM_GETSTATUS這個參數顯然是描述控制動作是獲得狀態。
&decDynParams 動態參數
&decStatus 狀態

關於這個函數的描述是:
第一個參數是算法實例的句柄,剩下的2個參數是算法特定的。返回值是IALG_EOK或是其它出錯信息。這個函數實現是可選的,如不實現設置爲空。

       調用條件:只能在algInit()後調用,handle是一個有效句柄,cmd的數值必須小於IALG_SYSCMD
實際上在xDM中control函數與ialg中的ialg_control還有些許不同,這裏先不理,下面直接看實現代碼:
/*
 *  ======== VIDENCCOPY_TI_control ========
 */
XDAS_Int32 VIDENCCOPY_TI_control(IVIDENC_Handle handle, IVIDENC_Cmd id,
    IVIDENC_DynamicParams *params, IVIDENC_Status *status)
{
    XDAS_Int32 retVal;

    GT_4trace(curTrace, GT_ENTER, "VIDENCCOPY_TI_control(0x%x, 0x%x, 0x%x, "
        "0x%x)\n", handle, id, params, status);


    /* validate arguments - this codec only supports "base" xDM. */
    if ((params->size != sizeof(*params)) ||
        (status->size != sizeof(*status))) {


        GT_2trace(curTrace, GT_ENTER,
            "VIDENCCOPY_TI_control, unsupported size "
            "(0x%x, 0x%x)\n", params->size, status->size);


        return (IVIDENC_EFAIL);
    }

    switch (id) {  //根據命令id來決定動作
        case XDM_GETSTATUS: //獲得狀態
        case XDM_GETBUFINFO: //獲得緩衝區信息
            status->extendedError = 0;
            status->bufInfo.minNumInBufs = MININBUFS; //填充狀態的信息域
            status->bufInfo.minNumOutBufs = MINOUTBUFS;
            status->bufInfo.minInBufSize[0] = MININBUFSIZE;
            status->bufInfo.minOutBufSize[0] = MINOUTBUFSIZE;

            retVal = IVIDENC_EOK;

            break;

        case XDM_SETPARAMS: //設定參數
        case XDM_SETDEFAULT: //設爲默認
        case XDM_RESET: //復位
        case XDM_FLUSH: //清空
            /* TODO - for now just return success. 現在只是返回EOK*/

            retVal = IVIDENC_EOK;
            break;

        default:
            /* unsupported cmd 如果是不支持的命令,則返回EFAIL*/
            retVal = IVIDENC_EFAIL;

            break;
    }

    return (retVal);
}


另一個和上面的區別不大,只是列出代碼,不做過多解釋,從這兩個代裏我們看到這裏有一個很重要的東西就是status結構體:
/*
 *  ======== VIDDECCOPY_TI_control ========
 */
XDAS_Int32 VIDDECCOPY_TI_control(IVIDDEC_Handle handle, IVIDDEC_Cmd id,
    IVIDDEC_DynamicParams *params, IVIDDEC_Status *status)
{
    XDAS_Int32 retVal;


    GT_4trace(curTrace, GT_ENTER, "VIDDECCOPY_TI_control(0x%lx, 0x%lx, 0x%lx, "
        "0x%lx)\n", handle, id, params, status);


    /* validate arguments - this codec only supports "base" xDM. */
    if ((params->size != sizeof(*params)) ||
        (status->size != sizeof(*status))) {

        GT_2trace(curTrace, GT_ENTER, "VIDDECCOPY_TI_control, unsupported size "
            "(0x%lx, 0x%lx)\n", params->size, status->size);

        return (IVIDDEC_EFAIL);
    }


    switch (id) {
        case XDM_GETSTATUS:
            status->extendedError = 0;
            status->outputHeight = 0;  /* TODO */
            status->outputWidth = 0;  /* TODO */
            status->frameRate = 0;  /* TODO */
            status->bitRate = 0;  /* TODO */
            status->contentType = 0;  /* TODO */
            status->outputChromaFormat = 0;  /* TODO */

            /* Note, intentionally no break here so we fill in bufInfo, too */


        case XDM_GETBUFINFO:
            status->bufInfo.minNumInBufs = MININBUFS;
            status->bufInfo.minNumOutBufs = MINOUTBUFS;
            status->bufInfo.minInBufSize[0] = MININBUFSIZE;
            status->bufInfo.minOutBufSize[0] = MINOUTBUFSIZE;

            retVal = IVIDDEC_EOK;

            break;


        case XDM_SETPARAMS:
        case XDM_SETDEFAULT:
        case XDM_RESET:
        case XDM_FLUSH:
            /* TODO - for now just return success. */

            retVal = IVIDDEC_EOK;
            break;


        default:
            /* unsupported cmd */
            retVal = IVIDDEC_EFAIL;

            break;
    }

    return (retVal);
}


樓上講的control函數實際上並非ialg接口定義的ialgcontrol函數,而是xDM定義的control函數,xDM還定義了一個process函數,這個函數是ialg沒有的.
簡單 起見去掉裏面的trace代碼:
/*
 *  ======== VIDDECCOPY_TI_process ========
 */
XDAS_Int32 VIDDECCOPY_TI_process(IVIDDEC_Handle h, XDM_BufDesc *inBufs,
    XDM_BufDesc *outBufs, IVIDDEC_InArgs *inArgs, IVIDDEC_OutArgs *outArgs)
{//傳入參數五個//0-->IVIDDEC_Handle,即解碼器實例句柄//1-->XDM_BufDesc *inBufs,一個xDM緩衝區描述符型的輸入緩衝區//-1-->XDC_BufDesc *outBufs,一個xDM緩衝區描述符型的輸出緩衝區//2-->IVIDDEC_InArgs型 傳入參數//-2-->傳出參數
    XDAS_Int32 curBuf;
    XDAS_Int32 minSamples;


    /* 驗證傳入傳出參數大小是否合法,不合法則返回失敗*/
    if ((inArgs->size != sizeof(*inArgs)) ||
        (outArgs->size != sizeof(*outArgs))) {
        return (IVIDDEC_EFAIL);
    }


    /* outArgs->bytesConsumed reports the total number of bytes consumed */
    outArgs->bytesConsumed = 0; //消耗的字節總數/*
     * A couple constraints for this simple "copy" codec:這個簡單複製算法的限制
     *    - Given a different number of input and output buffers, only //給定一組不同輸入和輸出緩衝區數目
     *      decode (i.e., copy) the lesser number of buffers.//只解碼較小數目的緩衝區
     *    - Given a different size of an input and output buffers, only//給定一組不同輸出輸入緩衝區大小
     *      decode (i.e., copy) the lesser of the sizes.//只解碼較小大小的字節數
     */


    for (curBuf = 0; (curBuf < inBufs->numBufs) &&
        (curBuf < outBufs->numBufs); curBuf++) {//for loop的條件:當前緩衝區序號同時小於輸入和輸出緩衝區數目


        /* there's an available in and out buffer, how many samples? 給定一組輸入輸入緩衝區,用多少樣本? */
        minSamples = inBufs->bufSizes[curBuf] < outBufs->bufSizes[curBuf] ?
            inBufs->bufSizes[curBuf] : outBufs->bufSizes[curBuf];  //minSamples爲inBufs結構的當前緩衝區大小和outBufs結構的當前緩衝區大小的最小值.


        /* process the data: read input, produce output 處理數擾,讀輸出,產生輸出*/
        memcpy(outBufs->bufs[curBuf], inBufs->bufs[curBuf], minSamples); //純的memcpy
outArgs->bytesConsumed += minSamples;//消耗的字節數增加minSamples個字節.
    }


    /* Fill out the rest of the outArgs struct 複製完之後,填充outArgs結構的其他域*/
    outArgs->extendedError = 0;
    outArgs->decodedFrameType = 0;     /* TODO */
    outArgs->outputID = inArgs->inputID;
    outArgs->displayBufs.numBufs = 0;  /* important: indicate no displayBufs */


    return (IVIDDEC_EOK);//返回成功
}

再看編碼器的代碼,裏面涉及了一段涉及使用ACPY3的算法,這裏先不理.
我們接着看這個代碼在app.c中是怎麼用的:
/*
     * Read complete frames from in, encode, decode, and write to out.*從輸入文件讀取,編碼,再解編,寫到輸出
     */
    for (n = 0; fread(inBuf, IFRAMESIZE, 1, in) == 1; n++) {//for loop從輸入文件每次讀一幀


#ifdef CACHE_ENABLED
#ifdef xdc_target__isaCompatible_64P
        /*
         *  fread() on this processor is implemented using CCS's stdio, which
         *  is known to write into the cache, not physical memory.  To meet
         *  xDAIS DMA Rule 7, we must writeback the cache into physical
         *  memory.  Also, per DMA Rule 7, we must invalidate the buffer's
         *  cache before providing it to any xDAIS algorithm.*fread在這個處理器上的實現是通過CCS工具實現的.是讀入cache的,不是物理內存,爲*満足xDAIS DMA規則7,我們必須從cache中寫加內存,而且必須驗證cache,再提供給算法.
         */
        Memory_cacheWbInv(inBuf, IFRAMESIZE);
#else
#error Unvalidated config - add appropriate fread-related cache maintenance
#endif
        /* Per DMA Rule 7, our output buffer cache lines must be cleaned */
        Memory_cacheInv(encodedBuf, EFRAMESIZE);
#endif


        GT_1trace(curMask, GT_1CLASS, "App-> Processing frame %d...\n", n);


        /* encode the frame */
        status = VIDENC_process(enc, &inBufDesc, &encodedBufDesc, &encInArgs,
            &encOutArgs);//這裏是process函數,參數是編碼器句柄,inBufDesc結構中有inBuf的指針,encodedBufDesc中有encodeBuf的指針,參數也是各自設置的.


        GT_2trace(curMask, GT_2CLASS,
            "App-> Encoder frame %d process returned - 0x%x)\n",
            n, status);


#ifdef CACHE_ENABLED
        /* Writeback this outBuf from the previous call.  Also, as encodedBuf
         * is an inBuf to the next process call, we must invalidate it also, to
         * clean buffer lines.
         */
        Memory_cacheWbInv(encodedBuf, EFRAMESIZE);


        /* Per DMA Rule 7, our output buffer cache lines must be cleaned */
        Memory_cacheInv(outBuf, OFRAMESIZE);
#endif


        if (status != VIDENC_EOK) {
            GT_3trace(curMask, GT_7CLASS,
                "App-> Encoder frame %d processing FAILED, status = 0x%x, "
                "extendedError = 0x%x\n", n, status, encOutArgs.extendedError);
            break;
        }


補充代碼:
/* clear and initialize the buffer descriptors */
    memset(src,     0, sizeof(src[0])     * XDM_MAX_IO_BUFFERS);
    memset(encoded, 0, sizeof(encoded[0]) * XDM_MAX_IO_BUFFERS);
    memset(dst,     0, sizeof(dst[0])     * XDM_MAX_IO_BUFFERS);


    src[0]     = inBuf;
    encoded[0] = encodedBuf;
    dst[0]     = outBuf;


    inBufDesc.numBufs = encodedBufDesc.numBufs = outBufDesc.numBufs = 1;


    inBufDesc.bufSizes      = inBufSizes;
    encodedBufDesc.bufSizes = encBufSizes;
    outBufDesc.bufSizes     = outBufSizes;


    inBufSizes[0] = encBufSizes[0] = outBufSizes[0] = NSAMPLES;


    inBufDesc.bufs      = src;
    encodedBufDesc.bufs = encoded;
    outBufDesc.bufs     = dst;


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章