opencoreamr移植至嵌入式设备
这段时间在做一个智能学生证项目。其中一个需求是做一个类似微信发语音的功能。由于录音保存的是PCM编码的wav格式音频,文件体积巨大。为了获得极致的压缩率,打算将PCM编码的音频文件转为AMR格式,需要移植opencoreamr库。
opencoreamr是用C和C编写的AMR音频编解码库,可以对AMRNB和AMRWB格式的音频进行编解码。要移植opencoreamr我们只需用对应的工具链编译出静态链接库即可。
opencoreamr源码下载地址:https:sourceforge。netprojectsopencoreamrfilesopencoreamrx86Linux下编译
1。下载并解压opencoreamr源码tarxvfopencoreamr0。1。3。tar。gz
2。opencoreamr使用configure脚本配置不同的参数。x86平台下,只需要指定‘prefix’参数即可,这个参数指定了完成编译后的头文件和库的保存位置,必须是绝对路径。如需了解其他参数,可以使用。configurehelp命令查看。。configureprefixhomejoshuaopencoreamrx86
3。配置好后,使用make进行编译和安装makemakeinstall
之后就可以到prefix设定的目录中查看编译好的库文件了。
嵌入式交叉编译
1。相比于x86,嵌入式平台需要指定交叉编译器进行配置。请确保环境变量中有交叉编译器的路径。。configurehostarmnoneeabiprefixhomejoshuaopencoreamrarm
如果有configure:error:Ccompilercannotcreateexecutables的错误提示,并且config。log中的报错信息为‘exit。c:(。text。exit0x2c):undefinedreferencetoexit’,该错误的原因可能是g编译器的版本不匹配,解决办法为在configure前增加编译参数specsnosys。specs。
2。还需注意的是,编译器参数最好和要使用该库的代码保持一致,否则可能出现浮点计算方式不同而不能正常链接的错误。exportOTHERLINKOPTIONSspecsnosys。specsexportGCCFLAGSstdgnu11mcpucortexa5mtunegenericarmv7amthumbmfpuneonvfpv4mfloatabihardmnounalignedaccessOsLDFLAGSOTHERLINKOPTIONSCFLAGSGCCFLAGSCXXFLAGSGCCFLAGS。configurehostarmnoneeabiprefixfsc02opencoreamr0。1。3openCPUPCM转AMR程序includestdio。hincludestdlib。hincludeinterfenc。hPCM参数definePCMSAMPLERATE(8000)只能编码8khzdefinePCMSAMPLEBITS(16)只支持16位definePCMCHANNELS(1)不管PCM输入是单声道还是双声道,这里输出的amr都是单声道的amr一帧数据是20ms,一秒50帧。8000,16,1320BytesdefinePCMONEFRAMESIZE(PCMSAMPLERATE50PCMSAMPLEBITS8PCMCHANNELS)AMR参数defineAMRENCODEMODEMR122defineAMRONEFRAMESIZE(32)MR122格式是32字节一帧是否使能背景噪声编码模式defineDTXDECODEENABLE1defineDTXDECODEDISABLE0intmain(intargc,charargv〔〕){intdtxDTXDECODEENABLE;voidvpAmrNULL;FILEfpAmrNULL;FILEfpPcmNULL;检查参数if(argc!3){printf(Usage:s。audiotest8000161。pcmout。amr,argv〔0〕);return1;}printf(ItwillencodeaPCMfileas〔samplerate:d〕〔samplebits:d〕〔channels:d〕!,PCMSAMPLERATE,PCMSAMPLEBITS,PCMCHANNELS);初始化编码器vpAmrEncoderInterfaceinit(dtx);if(vpAmrNULL){printf(EncoderInterfaceiniterror!);return1;}打开pcm文件fpPcmfopen(argv〔1〕,rb);if(fpPcmNULL){perror(argv〔1〕);return1;}打开amr文件fpAmrfopen(argv〔2〕,wb);if(fpAmrNULL){perror(argv〔2〕);return1;}先写入amr头部fwrite(!AMR,1,6,fpAmr);循环编码while(1){unsignedcharacPcmBuf〔PCMONEFRAMESIZE〕{0};保存在文件中一帧(20ms)PCM数据,8bit为单位,这里是unsignedshortasEncInBuf〔PCMONEFRAMESIZE2〕{0};编码需要的一帧(20ms)PCM数据,16bit为单位characEncOutBuf〔AMRONEFRAMESIZE〕{0};编码出来的一帧(20ms)AMR数据intiReadPcmBytes0;从PCM文件中读取出的数据大小,单位:字节intiEncAmrBytes0;编码出的AMR数据大小,单位:字节读出一帧PCM数据iReadPcmBytesfread(acPcmBuf,1,PCMONEFRAMESIZE,fpPcm);if(iReadPcmBytes0){break;}printf(iReadPcmBytesd,iReadPcmBytes);if0编码方式1:像官方测试程序一样转换为short类型再进行编码for(inti0;iPCMONEFRAMESIZE2;i){unsignedcharpacPcmBuf〔2PCMCHANNELSi〕;asEncInBuf〔i〕(p〔1〕8)p〔0〕;}编码iEncAmrBytesEncoderInterfaceEncode(vpAmr,AMRENCODEMODE,asEncInBuf,acEncOutBuf,0参数未使用);else编码方式2:传参时直接类型强制转换即可编码iEncAmrBytesEncoderInterfaceEncode(vpAmr,AMRENCODEMODE,(short)acPcmBuf,acEncOutBuf,0参数未使用);endifprintf(iEncAmrBytesd,iEncAmrBytes);写入到AMR文件中fwrite(acEncOutBuf,1,iEncAmrBytes,fpAmr);}关闭文件fclose(fpAmr);fclose(fpPcm);关闭编码器EncoderInterfaceexit(vpAmr);printf(ss:Success!,argv〔1〕,argv〔2〕);return0;}