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;


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值