近段时间一直在忙碌AMR音频解码插件的开发,由于对驱动开发和音频编解码知识了解不是很多,加之自身经验欠缺,致使开发过程中碰到太多棘手的问题。经过努力学习和领导的大力帮助下终于完成了插件的开发,现将开发过程中得来的经验总结下来,为近段时间自己学来的东西理个头绪,也为今后有类似开发的朋友一个参考。


AMR解码插件开发之环境配置



本文开发此插件是在Windows XP环境下进行,需要安装WinXPDDK进行编译,另外需要AMR-NB(Adaptive Multi-Rate Narrowband)编解码相对应的动态链接库。(由于WinDDK的调试非常困难,在开发过程中经常弄不清楚问题出在什么地方,所以使用写文件日志和MessageBox的方法进行跟踪调试,但是此调试手段实在太耗神。。。有文章介绍可以安装WindDbg来进行调试,由于时间紧任务急没来得及研究,以后研究学习。。)

安装及配置步骤:

1.       安装WinXPDDK(最好按照默认的路径进行安装,要进行Audio音频插件开发,所以对应的audio组建最好选上)

2.       在C:\WINDDK\2600\src\wdm\audio下创建AMR工程

3.       配置工程对应的编译环境:修改\audio目录下对应的dirs文件,将编译路径设为amr文件夹;sources文件中规定了编译生成的文件名、文件类型、链接库配置、编译的对应文件*.c等文件;另外需要改动的配置文件有:amr.def指明了工程入口;camr.inf安装配置文件;这些文件的配置按照安装的Audio模板修改相应的参数即可。

4.       编译:开始->程序->Development Kits->Windows DDK 2600->Build Enviroments->Win XP Checked Build Environment,在弹出的窗口中输入build即可。

5.       编译后生成的文件在..\AMR\\objchk\i386中,文件名为*.acm,将camr.inf文件拷入此文件夹下,鼠标选中右键点击安装即可,相应的信息便写入注册表。(查看是否正确安装:控制面板的设备管理器->声音、视频和游戏控制器->音频编码解码器->属性,查看对应的音频编解码器列表中是否存在)


 

AMR解码插件开发之ACM音频编解码管理器

ACM是通用的音频编解码管理器,固定的接口函数为:DriverProc,通过不同的消息uMsg来调用不同的函数,下面列出在开发过程中可能需要改动的函数:

DRV_LOAD               驱动加载

DRV_FREE                驱动退出

DRV_OPEN               打开插件

DRV_CLOSE             关闭插件

DRV_CONFIGURE 配置插件

ACMDM_FORMAT_DETAILS 根据FormatTag设置文件存储的音频参数

ACMDM_FORMATTAG_DETAILS 得到指定的FormatTag的ACMFORMATTAGDETAILS

ACMDM_STREAM_OPEN 音频流打开,确定是编码流还是解码流,做相应的初始化工作,调用相对应的编\解码初始化函数、

ACMDM_STREAM_CLOSE 关闭音频流,做相对应的内存释放工作和对应的编\解码退出函数

ACMDM_STREAM_SIZE 设置音频流的SrcLength和DstLength

ACMDM_STREAM_CONVERT 调用编\解码函数。

具体的工作需要具体解决。


AMR解码插件开发之动态调用DLL


众所周之,动态链接库在VC中的方法有很多种,因为在开发过程中碰到了动态链接库的调用问题,所以将标准库调用方法总结一下。

VC中常使用方法:

方法一:直接在Project->Settings->Link中进行添加

方法二:使用#pragma comment(lib, “*.lib”)进行调用

方法三:动态LoadLibrary进行调用(1.LoadLibrary,装载动态库;2.GetProcAddress:获取要引入的函数,将符号名或标识号转换为DLL内部地址;3.FreeLibrary,释放动态链接库)

可能是提供给的AMR动态链接库和静态链接库存在一些错误,在Sources文件中TARGETLIBS直接添加对应的链接库后进行函数调用总是编译报错,所以经过尝试后终于用动态Load方式解决的标准库无法调用的问题。

本文方法如下:

首先在头文件中定义动态加载DLL的变量和需要使用的函数指针:

// 动态加载Dll
HMODULE hDllLib;
// 定义函数指针,用于动态加载dll来调用函数
typedef HI_S32 (*AMRDecodeInit)(HI_VOID **);
typedef HI_S32 (*AMRDecodeFrame)(HI_VOID *, HI_U8 *, HI_S16 *, enum Format);
typedef HI_S32 (*AMRGetLength)(enum Format, HI_U8);
typedef HI_VOID (*AMRDecodeExit)(HI_VOID **);
 
//标准库中对应函数的地址
AMRDecodeInit              amr_Decode_init;
AMRDecodeFrame           amr_Decode_Frame;
AMRDecodeExit               amr_Decode_Exit;
AMRGetLength                amr_Get_Length;

 

然后初始化时进行动态加载Dll和记录对应函数的地址

//动态加载用到的Dll
hDllLib = LoadLibrary("lib_amr_dll.dll");
if (hDllLib != NULL)
{
amr_Decode_init = (AMRDecodeInit)GetProcAddress(hDllLib, "AMR_Decode_Init");
…
}

在结束时要释放动态链接库:

// 释放动态加载的Dll
if (NULL != hDllLib)
{
         FreeLibrary(hDllLib);
         hDllLib = NULL;
}

 


   今天就先总结这么多,还有很多很多不懂的问题需要学习和解决。文中有不妥和理解错误的地方,还请读者多多指出。