使用 Codec Engine 的 API 函数(三)
2019-07-13 20:52 发布
生成海报
本文翻译自TI的手册,该手册是学习GPP+DSP开发的金典文档,希望对各位入门有所帮助,有理解不当之处望请赐教。 Codec Engine Application Developer User's Guide.pdf (Literature Number: SPRUE67D) 《Codec Engine 应用开发使用手册》 http://blog.csdn.net/dyzok88/article/details/42154487 《第一章 Codec Engine 概要》 http://blog.csdn.net/dyzok88/article/details/42214813 《第二章 Codec Engine 安装和设置》 http://blog.csdn.net/dyzok88/article/details/42278109 《第三章 使用 Codec Engine 的示例应用程序》 http://blog.csdn.net/dyzok88/article/details/42302793
// 正文
第4章 使用 Codec Engine 的 API 函数
4.3 VISA 类: 视频,图像,语音,音频
以下 API 函数被提供给每个 VISA 类的编码器( encoder )和解码器( decoder )双方,其中,MOD是模块的前缀:
1. MOD_create. 创建该类型算法的一个实例。 Create an instance of this type of algorithm. 2. MOD_process. 在此算法的实例上执行 "process" 的方法。 3. MOD_control. 在此算法的实例上执行 "control" 的方法。
4. MOD_delete. 删除此类型算法的指定实例。
4.3.1 VISA API 配置代码
对于应用程序使用的每个 VISA API 模块,你应该包括相应的头文件。例如,下面的语句包括用于音频解码器 API 模块的头文件,目录路径是相对于 CE_INSTALL_DIR/packages 软件包库。
#include
4.3.2 创建算法实例
在引擎内创建一个算法实例,为合适的VISA 编码器或解码器模块使用 *_create() 函数即可。
Engine_Handle ce;
AUDDEC_Handle dec;
static String decoderName = "auddec_copy";
/* allocate and initialize audio decoder on the Engine */
dec = AUDDEC_create(ce, decoderName, NULL);
在此函数中,第一个参数-ce-是 Engine_Handle 类型,该类型由 Engine_open() 函数返回。
第二个参数-decoderName-是一个字符串,用来标识要创建的算法类型。这些字符串是由系统集成工程师创建的配置文件的一部分。
第三个参数允许你在实例化算法时指定要使用的参数, 这些参数控制算法的行为方面。参数 的 结构 体与 每个 VISA 编码器或解码器类不同。例如,音频解码器参数结构 体 如下:
typedef struct IAUDDEC_Params {
XDAS_Int32 size; /* Size of this structure */
XDAS_Int32 maxSampleRate; /* Max sampling freq in Hz */
XDAS_Int32 maxBitrate; /* Max bit-rate in bits per sec */
XDAS_Int32 maxNoOfCh; /* Max number of channels */
XDAS_Int32 dataEndianness; /* Endianness of input data */
} IAUDDEC_Params;
此函数返回一个的用于其它函数访问算法实例的句柄。
4.3.3 删除算法实例
要删除一个算法实例,并释放其占用的内存,您的应用程序应该调用 MOD_delete()。例如:
/* tear down the codec and Engine */
AUDDEC_delete(dec);
你应该在已经释放完所有的缓冲区或其他内存相关的算法实例之后这样做。
4.3.4 控制算法实例
使用模块的 *_control() 函数可以控制和查询算法的功能。
例如,下面的代码使用 AUDDEC_control() 函数来查询一个解码器,以验证解码器接受一个输入缓冲器,返回一个输出缓冲器,使用 buffer sizes,可以处理 NSAMPLES 字节的数据。
#define NSAMPLES 1024
#define IFRAMESIZE (NSAMPLES * sizeof(Int8)) /* raw (in) */
#define OFRAMESIZE (NSAMPLES * sizeof(Int8)) /* decoded */
static Char inBuf[IFRAMESIZE];
static Char outBuf[OFRAMESIZE];
XDM_BufDesc inBufDesc;
XDM_BufDesc outBufDesc;
XDAS_Int32 status;
XDAS_Int32 bufSizes = NSAMPLES;
IAUDDEC_DynamicParams decDynParams;
IAUDDEC_Status decStatus;
/* prepare "global" buffer descriptor settings */
inBufDesc.numBufs = outBufDesc.numBufs = 1;
inBufDesc.bufSizes = outBufDesc.bufSizes = &bufSizes;
/* Query the decoder */
status = AUDDEC_control(dec, XDM_GETSTATUS, &decDynParams,
&decStatus);
if (status != AUDDEC_EOK) {
/* failure, report error and exit */
printf("decode control status = %ld
", status);
return;
}
/* Validate decoder codec will meet buffer requirements */
if ((inBufDesc.numBufs > decStatus.bufInfo.maxNumInBufs) ||
(sizeof(inBuf) > decStatus.bufInfo.maxInBufSize[0]) ||
(outBufDesc.numBufs > decStatus.bufInfo.maxNumOutBufs) ||
(sizeof(outBuf) > decStatus.bufInfo.maxOutBufSize[0])) {
/* failure, report error and exit */
printf("Error: decoder codec feature conflict
");
return;
}
在 AUDDEC_control() 函数的例子中,第一个参数-dec-是由 AUDDEC_create() 函数返回的算法的句柄( handle )。
第二个参数是 来自 xdm.h 文件的 命令 ID 常量 ,该常量的 选项有: 1. XDM_GETSTATUS. 查询算法 ,并且 填充包含有关该算法功能的状态信息结构 体 。 2. XDM_SETPARAMS. 设置该算法运行时间 的 动态参数。 3. XDM_GETPARAMS. 获得 该算法运行时动态参数的当前设置 。
4. XDM_RESET. 重置算法。 在 错误或数据丢失 发生 后 , 可能会运行初始化函数或特殊函数 进行 恢复。
5. XDM_SETDEFAULT. 设置所有参数为默认值。
6. XDM_FLUSH. 流条件结束 后 处理 ,不管有没有额外的输入,强制算法输出。推荐的顺序是调用 *_control() API 带参数XDM_FLUSH,然后进行重复调用 *_process() API 。
7. XDM_GETBUFINFO. 查询算法实例 , 关于其输入和输出缓冲器的属性 。
欲了解更多有关XDM,请参考xDAIS-DM(数字媒体)用户指南( SPRUEC8 )。
如果使用了指定的 XDM_SETPARAMS 或 XDM_GETPARAMS 命令代码,第三个参数便是一个动态参数结构体的地址,这种结构体与 VISA 编码器和解码器模块的结构体不同。
如果使用了指定的 XDM_GETSTATUS 命令代码,第四个参数是一个状态结构体的地址,这种结构体与 VISA 编码器和解码器模块的结构体也不同。
4.3.5 算法实例的数据处理
您可以使用模块的 *_process() 函数运行算法。
例如,下面的代码继续前一节中的例子。它使用 AUDDEC_process() 函数从 "in" 读取帧,解码音频,然后将输出写入到 "out"。
Int n;
XDM_BufDesc inBufDesc;
XDM_BufDesc outBufDesc;
IAUDDEC_InArgs decInArgs;
IAUDDEC_OutArgs decOutArgs;
/* prepare "global" buffer descriptor settings */
inBufDesc.numBufs = outBufDesc.numBufs = 1;
inBufDesc.bufSizes = outBufDesc.bufSizes = &bufSizes;
decInArgs.size = sizeof(decInArgs);
...
/* Read complete frames from in, decode and write to out */
for (n = 0; fread(inBuf, sizeof (inBuf), 1, in) == 1; n++) {
XDAS_Int8 *src = inBuf;
XDAS_Int8 *dst = outBuf;
/* prepare "per loop" buffer descriptor settings */
inBufDesc.bufs = &src;
outBufDesc.bufs = &dst;
decInArgs.size = sizeof(decInArgs);
decInArgs.numBytes = sizeof(inBuf);
/* decode the frame */
status = AUDDEC_process(dec, &inBufDesc, &outBufDesc,
&decInArgs, &decOutArgs);
if (status != AUDDEC_EOK) {
printf("frame %d: decode status = %ld
", n, status);
}
/* write to file */
fwrite(dst, sizeof (outBuf), 1, out);
}
printf("%d frames decoded
", n);
在 AUDDEC_process() 函数的例子中,第一个参数-dec-是由 AUDDEC_create() 函数返回的算法的句柄( handle )。
对于音频解码器模块(对于大多数其它 VISA 模块)的第二和第三个参数 ,提供类型为 XDM_BufDesc 的缓冲区描述符结构体的地址。这种类型的结构如下定义:
typedef struct XDM_BufDesc {
XDAS_Int8 **bufs;
XDAS_Int32 numBufs;
XDAS_Int32 *bufSizes;
} XDM_BufDesc;
对于音频解码器模块(对于大多数其它 VISA 模块)的 第四个和第五个参数,提供对于该算法的输入和输出参数的地址。这种结构体与 VISA 编码器和解码器模块的结构体不同。
4.3.6 重写 远程算法的优先级和内存请求
4.3.6.1 重写 算法的配置的优先级
在某些情况下,应用程序开发人员可能希望在不同的优先级上运行远程编解码器的多个实例。 作为一个例子 ,假设你要运行采样音频编码器副本编解码器的两个实例:一个优先级为4,另一个优先级为5。包含该编解码器的服务器中,最初配置的音频编码器运行在优先级4上,正如显示在下面的配置代码(假设 Server.MINPRI 是1)。
Server.algs = [
{name: "audenc_copy", mod: AUDENC_COPY, threadAttrs: {
stackMemId: 0, priority: Server.MINPRI + 3}
},
...
];
解决这个问题是似乎是通过配置DSP服务器,通过增加另一个音频编码器,该编码器使用新的优先级和与服务器算法列表不同的名称,具体如下:
Server.algs = [
/* Audio copy encoder configured with priority 4 */
{name: "audenc_copy", mod: AUDENC_COPY, threadAttrs: {
stackMemId: 0, priority: Server.MINPRI + 3}
},
/* Audio copy encoder configured with priority 5 (WRONG)*/
{name: "audenc_copy_2", mod: AUDENC_COPY, threadAttrs: {
stackMemId: 0, priority: Server.MINPRI + 4}
},
...
];
然而,试图重建服务器时,由于为这两个编解码器生成 UUIDs,这会导致错误出现。UUIDs 通过 MOD( AUDENC_COPY )配置参数确定,结果是完全相同的。由于是 UUID,而不是编解码器的名称,信息从ARM应用到DSP服务器内部通过并实例化编解码器,这两个编解码器将无法区分。因此,这种方法是行不通的。
创建一个优先级不同于 DSP 服务器配置的编解码器的正确方法是,通过传递名称参数给 MOD_cr eate() API, 其中MOD,是 VISA 的模块之一。该名称是将编解码器的名称与重写( overriding )优先级附加到它,用“:”分隔。例如,如上图所示运行在优先级5的音频编码器,通过传递名称为" audenc_copy:5 " 至 AUDENC_create() 函数 。下面的代码片段创建两个音频编码器的副本,在不同的优先级运行(不对可读性进行错误检查)
Engine_Handle ce;
AUDENC_Handle enc;
AUDENC_Handle enc_high;
ce = Engine_open("audio_copy", NULL, NULL);
/* Create codec at the configured priority */
enc = AUDENC_create(ce, "audenc_copy", NULL);
/* Create second instance of codec, overriding the
* configured priority with a priority of 5 */
enc_high = AUDENC_create(ce, "audenc_copy:5", NULL) ;
4.3.6.2 重写算法的内存请求
编解码器分配缓冲区位置的请求是可以被忽略的,编解码器可以强制所有编解码器的内存请求分配在外部堆,DSKT2 模块的 ESDATA 配置参数上可以映射到该堆。
通过附加传递给 MOD_create() 函数的编解码器名称可以实现上面功能,要重写内存位置的请求,追加" :1 "到 优先级调整后的名称后面。例如,下面传给 AUDENC_create() 的名称具有以下含义:
1. "audenc_copy:5:1" 创建优先级5,分配的外部内存缓冲区的 audenc_copy。 2. "audenc_copy::1" 创建其配置的优先级,分配在外部存储器缓冲区的 audenc_copy。
追加" ::0 "到编解码器名称(或 " :0 ",如果一个新的优先级也追加),意味着该编解码器的内存请求应得到重视,传递下面的名称到 AUDENC_create() 是等价的:
1. "audenc_copy" 2. "audenc_copy::0"
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮