写可以被CE使用的算法通常要实现XDAIS或xDM标准。xDM是XDAIS的扩展。xDM自己又包括八种接口,按音频,视频,图像,语音每个再分为编码器和解码器。xDM和XDAIS的关系如图所示。
XDAIS标准分为两个接口,一个是IALG和个是IMOD。其框架如图所示。而xDM则是在XDAIS的基础上增加了一个接口,其框架图如图所示。
首先我们要先了解xDAIS的ialg接口:
ialg接口有七个函数需要我们去实现,这个链接是七个函数的调用流程。这七个函数组成一个结构体称为ialgfxns.其结构原型为:
有些时候其中的一些函数无需实现,但要赋值为NULL.结构体中只有第一个成员变量比较特殊,不是函数指针而是一个空指针,它的作用是唯一标识模块的实现,经常需要用到。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;
另一个,viddec_copy的内容是一样的:/* * ======== 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); //只做了一个表项,返回一。 }
/* * ======== 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); }
第一个参数是算法实例的句柄,剩下的2个参数是算法特定的。返回值是IALG_EOK或是其它出错信息。这个函数实现是可选的,如不实现设置为空。
调用条件:只能在algInit()后调用,handle是一个有效句柄,cmd的数值必须小于IALG_SYSCMD
/* * ======== 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); }
楼上讲的control函数实际上并非ialg接口定义的ialgcontrol函数,而是xDM定义的control函数,xDM还定义了一个process函数,这个函数是ialg没有的./* * ======== 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); }
再看编码器的代码,里面涉及了一段涉及使用ACPY3的算法,这里先不理./* * ======== 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);//返回成功 }
补充代码:/* * 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;