嵌入式linux:音频编解码PCM转至AAC
2016-03-10 17:04
597 查看
作者:柳大·Poechant
博客:blog.csdn.net/poechant
邮箱:zhongchao.ustc@gmail.com
日期:April 7th, 2012
这里利用FAAC来实现AAC编码。
这里的安装过程是在 Mac 和 Linux 上实现的,Windows可以类似参考。
FAAC开源工程源码下载链接:FAAC源码下载
得到FAAC工程源码后首先执行 configure获得Makefile,并指定目标平台和交叉工具链
./configure--target=arm-linux--host=arm-none-linux-gnueabi
编译:
make
安装:
make install
如果才用默认的 configure 中的 prefix path,那么安装后的 lib 和 .h 文件分别在
如果编译过程中发现错误:
解决方法:
从123行开始修改此文件mpeg4ip.h,到129行结束。 修改前:
修改后:
获取编码器的配置:
设定编码器的配置:
采样率,声道数(双声道还是单声道?),还有你的PCM的单个样本是8位的还是16位的?
调用
根据
调用
调用
关闭编码器,另外别忘了释放缓冲区,如果使用了文件流,也别忘记了关闭。
我的程序是根据faac 1.28 库中的frontend目录下的faac的例子改的。
下面是程序的运行流程:
首先调用faacEncHandle hEncoder=faacEncOpen(samplerate,channels,& samplesInput,
&maxBytesOutput);
1.打开aac编码引擎,创建aac编码句柄。
参数 samplerate 为要编码的音频pcm流的采样率,channels为要编码的音频pcm流的的频道数(原有的例子程序是从wav文件中读出这些信息),sampleInput在编码时要用到,意思是每次要编码的采样数,参数maxBytesOutput为编码时输出地最大字节数。
2.然后在设置一些编码参数,如
int version=MPEG4; //设置版本,录制MP4文件时要用MPEG4
int objecttype=LOW; //编码类型
int midside=1; //M/S编码
int usetns=DEFAULT_TNS; //瞬时噪声定形(temporal noise shaping,TNS)滤波器
int shortctl=SHORTCTL_NORMAL;
int inputformat=FAAC_INPUT_16BIT; //输入数据类型
int outputformat=RAW_STREAM; //录制MP4文件时,要用raw流。检验编码是否正确时可设
//置为adts传输流,把aac 流写入.aac文件中,如编码正确
//用千千静听就可以播放。
其他的参数可根据例子程序设置。
设置完参数后就调用faacEncSetConfiguration(hEncoder, aacFormat)设置编码参数。
3.如编码完的aac流要写入MP4文件时,要调用
faacEncGetDecoderSpecificInfo(hEncoder,&(ASC), &(ASCLength));//得到解码信息
//(mpeg4ip mp4 录制使用)
此函数支持MPEG4版本,得到的ASC 和ACSLength 数据在录制MP4(mpegip库)文件时用。
4.然后就是编码了,每次从实时的pcm音频队列中读出samplesInput* channels*(量化位数/8),
字节数的pcm数据。然后再把得到pcm流转变一下存储位数,我是转化为16位的了,这部分
可以根据例子程序写一个函数,这是我写的一个,
size_t read_int16(AACInfo *sndf, int16_t *outbuf, size_t num, unsigned char *inputbuf)
{
size_t i=0,j=0;
unsigned char bufi[8];
while(i<num)
{
memcpy(bufi,inputbuf+j,sndf->samplebytes);
j+=sndf->samplebytes;
int16_t s=((int16_t*)bufi)[0];
outbuf[i]=s;
i++;
}
return i;
}
也可以写一个read_float32(AACInfo *sndf, float *outbuf, size_t num ,unsigned char *inputbuf),
和size_t read_int24(AACInfo *sndf, int32_t *outbuf, size_t num, unsigned char *inputbuf)。
处理完数据转换后就调用
bytesWritten = faacEncEncode(hEncoder,
(int *)pcmbuf,
samplesInput,
outbuff,
maxbytesoutput);
进行编码,pcmbuf为转换后的pcm流数据,samplesInput为调用faacEncOpen时得到的输入采样数,outbuff为编码后的数据buff,maxbytesoutput为调用faacEncOpen时得到的最大输出字节数。然后每次从outbuff中得到编码后的aac数据流,放到数据队列就行了,如果还要录制MP4文件,在编码完samplesInput(一帧)个采样数时,打上时间戳(mpegip库用于音视频同步)后再放到输出队列中。如果想测试看编码的aac流是否正确,设置输出格式为ADTS_STREAM,把aac数据写入到.aac文件中,看能否用千千静听播放。
5.释放资源,调用faacEncClose(hEncoder);就行了
将
将上述代码保存为“pcm2aac.cpp”文件,然后编译:
运行:
然后就生成了
AudioCoding.com - FAAC
Dogfoot – 재밌는 개발
-
转载请注明来自柳大的CSDN博客:blog.csdn.net/poechant
博客:blog.csdn.net/poechant
邮箱:zhongchao.ustc@gmail.com
日期:April 7th, 2012
这里利用FAAC来实现AAC编码。
1 下载安装 FAAC
这里的安装过程是在 Mac 和 Linux 上实现的,Windows可以类似参考。FAAC开源工程源码下载链接:FAAC源码下载
得到FAAC工程源码后首先执行 configure获得Makefile,并指定目标平台和交叉工具链
./configure--target=arm-linux--host=arm-none-linux-gnueabi
编译:
make
安装:
make install
wget http://downloads.sourceforge.net/faac/faac-1.28.tar.gz tar zxvf faac-1.28.tar.gz cd faac-1.28 ./configure make sudo make install
如果才用默认的 configure 中的 prefix path,那么安装后的 lib 和 .h 文件分别在
/usr/local/lib和
/usr/local/include,后面编译的时候会用到。
如果编译过程中发现错误:
mpeg4ip.h:126: error: new declaration ‘char* strcasestr(const char*, const char*)’
解决方法:
从123行开始修改此文件mpeg4ip.h,到129行结束。 修改前:
#ifdef __cplusplus extern "C" { #endif char *strcasestr(const char *haystack, const char *needle); #ifdef __cplusplus } #endif
修改后:
#ifdef __cplusplus extern "C++" { #endif const char *strcasestr(const char *haystack, const char *needle); #ifdef __cplusplus } #endif
2 FAAC API
2.1 Open FAAC engine
Prototype:
faacEncHandle faacEncOpen // 返回一个FAAC的handle ( unsigned long nSampleRate, // 采样率,单位是bps unsigned long nChannels, // 声道,1为单声道,2为双声道 unsigned long &nInputSamples, // 传引用,得到每次调用编码时所应接收的原始数据长度 unsigned long &nMaxOutputBytes // 传引用,得到每次调用编码时生成的AAC数据的最大长度 );
2.2 Get/Set encoding configuration
Prototype:
获取编码器的配置:faacEncConfigurationPtr faacEncGetCurrentConfiguration // 得到指向当前编码器配置的指针 ( faacEncHandle hEncoder // FAAC的handle );
设定编码器的配置:
int FAACAPI faacEncSetConfiguration ( faacDecHandle hDecoder, // 此前得到的FAAC的handle faacEncConfigurationPtr config // FAAC编码器的配置 );
2.3 Encode
Prototype:
int faacEncEncode ( faacEncHandle hEncoder, // FAAC的handle short *inputBuffer, // PCM原始数据 unsigned int samplesInput, // 调用faacEncOpen时得到的nInputSamples值 unsigned char *outputBuffer,// 至少具有调用faacEncOpen时得到的nMaxOutputBytes字节长度的缓冲区 unsigned int bufferSize // outputBuffer缓冲区的实际大小 );
2.4 Close FAAC engine
Prototype
void faacEncClose ( faacEncHandle hEncoder // 此前得到的FAAC handle );
3 流程
3.1 做什么准备?
采样率,声道数(双声道还是单声道?),还有你的PCM的单个样本是8位的还是16位的?
3.2 开启FAAC编码器,做编码前的准备
调用faacEncOpen开启FAAC编码器后,得到了单次输入样本数
nInputSamples和输出数据最大字节数
nMaxOutputBytes;
根据
nInputSamples和
nMaxOutputBytes,分别为PCM数据和将要得到的AAC数据创建缓冲区;
调用
faacEncGetCurrentConfiguration获取当前配置,修改完配置后,调用
faacEncSetConfiguration设置新配置。
3.3 开始编码
调用faacEncEncode,该准备的刚才都准备好了,很简单。
3.4 善后
关闭编码器,另外别忘了释放缓冲区,如果使用了文件流,也别忘记了关闭。我的程序是根据faac 1.28 库中的frontend目录下的faac的例子改的。
下面是程序的运行流程:
首先调用faacEncHandle hEncoder=faacEncOpen(samplerate,channels,& samplesInput,
&maxBytesOutput);
1.打开aac编码引擎,创建aac编码句柄。
参数 samplerate 为要编码的音频pcm流的采样率,channels为要编码的音频pcm流的的频道数(原有的例子程序是从wav文件中读出这些信息),sampleInput在编码时要用到,意思是每次要编码的采样数,参数maxBytesOutput为编码时输出地最大字节数。
2.然后在设置一些编码参数,如
int version=MPEG4; //设置版本,录制MP4文件时要用MPEG4
int objecttype=LOW; //编码类型
int midside=1; //M/S编码
int usetns=DEFAULT_TNS; //瞬时噪声定形(temporal noise shaping,TNS)滤波器
int shortctl=SHORTCTL_NORMAL;
int inputformat=FAAC_INPUT_16BIT; //输入数据类型
int outputformat=RAW_STREAM; //录制MP4文件时,要用raw流。检验编码是否正确时可设
//置为adts传输流,把aac 流写入.aac文件中,如编码正确
//用千千静听就可以播放。
其他的参数可根据例子程序设置。
设置完参数后就调用faacEncSetConfiguration(hEncoder, aacFormat)设置编码参数。
3.如编码完的aac流要写入MP4文件时,要调用
faacEncGetDecoderSpecificInfo(hEncoder,&(ASC), &(ASCLength));//得到解码信息
//(mpeg4ip mp4 录制使用)
此函数支持MPEG4版本,得到的ASC 和ACSLength 数据在录制MP4(mpegip库)文件时用。
4.然后就是编码了,每次从实时的pcm音频队列中读出samplesInput* channels*(量化位数/8),
字节数的pcm数据。然后再把得到pcm流转变一下存储位数,我是转化为16位的了,这部分
可以根据例子程序写一个函数,这是我写的一个,
size_t read_int16(AACInfo *sndf, int16_t *outbuf, size_t num, unsigned char *inputbuf)
{
size_t i=0,j=0;
unsigned char bufi[8];
while(i<num)
{
memcpy(bufi,inputbuf+j,sndf->samplebytes);
j+=sndf->samplebytes;
int16_t s=((int16_t*)bufi)[0];
outbuf[i]=s;
i++;
}
return i;
}
也可以写一个read_float32(AACInfo *sndf, float *outbuf, size_t num ,unsigned char *inputbuf),
和size_t read_int24(AACInfo *sndf, int32_t *outbuf, size_t num, unsigned char *inputbuf)。
处理完数据转换后就调用
bytesWritten = faacEncEncode(hEncoder,
(int *)pcmbuf,
samplesInput,
outbuff,
maxbytesoutput);
进行编码,pcmbuf为转换后的pcm流数据,samplesInput为调用faacEncOpen时得到的输入采样数,outbuff为编码后的数据buff,maxbytesoutput为调用faacEncOpen时得到的最大输出字节数。然后每次从outbuff中得到编码后的aac数据流,放到数据队列就行了,如果还要录制MP4文件,在编码完samplesInput(一帧)个采样数时,打上时间戳(mpegip库用于音视频同步)后再放到输出队列中。如果想测试看编码的aac流是否正确,设置输出格式为ADTS_STREAM,把aac数据写入到.aac文件中,看能否用千千静听播放。
5.释放资源,调用faacEncClose(hEncoder);就行了
4 测试程序
4.1 完整代码
将PCM格式音频文件
/home/michael/Development/testspace/in.pcm转至
AAC格式文件
/home/michael/Development/testspace/out.aac。
#include <faac.h> #include <stdio.h> typedef unsigned long ULONG; typedef unsigned int UINT; typedef unsigned char BYTE; typedef char _TCHAR; int main(int argc, _TCHAR* argv[]) { ULONG nSampleRate = 11025; // 采样率 UINT nChannels = 1; // 声道数 UINT nPCMBitSize = 16; // 单样本位数 ULONG nInputSamples = 0; ULONG nMaxOutputBytes = 0; int nRet; faacEncHandle hEncoder; faacEncConfigurationPtr pConfiguration; int nBytesRead; int nPCMBufferSize; BYTE* pbPCMBuffer; BYTE* pbAACBuffer; FILE* fpIn; // PCM file for input FILE* fpOut; // AAC file for output fpIn = fopen("/home/michael/Development/testspace/in.pcm", "rb"); fpOut = fopen("/home/michael/Development/testspace/out.aac", "wb"); // (1) Open FAAC engine hEncoder = faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes); if(hEncoder == NULL) { printf("[ERROR] Failed to call faacEncOpen()\n"); return -1; } nPCMBufferSize = nInputSamples * nPCMBitSize / 8; pbPCMBuffer = new BYTE [nPCMBufferSize]; pbAACBuffer = new BYTE [nMaxOutputBytes]; // (2.1) Get current encoding configuration pConfiguration = faacEncGetCurrentConfiguration(hEncoder); pConfiguration->inputFormat = FAAC_INPUT_16BIT; // (2.2) Set encoding configuration nRet = faacEncSetConfiguration(hEncoder, pConfiguration); for(int i = 0; 1; i++) { // 读入的实际字节数,最大不会超过nPCMBufferSize,一般只有读到文件尾时才不是这个值 nBytesRead = fread(pbPCMBuffer, 1, nPCMBufferSize, fpIn); // 输入样本数,用实际读入字节数计算,一般只有读到文件尾时才不是nPCMBufferSize/(nPCMBitSize/8); nInputSamples = nBytesRead / (nPCMBitSize / 8); // (3) Encode nRet = faacEncEncode( hEncoder, (int*) pbPCMBuffer, nInputSamples, pbAACBuffer, nMaxOutputBytes); fwrite(pbAACBuffer, 1, nRet, fpOut); printf("%d: faacEncEncode returns %d\n", i, nRet); if(nBytesRead <= 0) { break; } } /* while(1) { // (3) Flushing nRet = faacEncEncode( hEncoder, (int*) pbPCMBuffer, 0, pbAACBuffer, nMaxOutputBytes); if(nRet <= 0) { break; } } */ // (4) Close FAAC engine nRet = faacEncClose(hEncoder); delete[] pbPCMBuffer; delete[] pbAACBuffer; fclose(fpIn); fclose(fpOut); //getchar(); return 0; }
4.2 编译运行
将上述代码保存为“pcm2aac.cpp”文件,然后编译:g++ pcm2aac.cpp -o pcm2aac -L/usr/local/lib -lfaac -I/usr/local/include
运行:
./pcm2aac
然后就生成了
out.aac文件了,听听看吧!~
5 Reference
AudioCoding.com - FAACDogfoot – 재밌는 개발
-
转载请注明来自柳大的CSDN博客:blog.csdn.net/poechant
相关文章推荐
- linux 获取文件系统信息(磁盘信息)
- 在CentOS 6.3 64bit下yum安装MySQL后重置root密码的方法
- 【Linux调试经验】局域网内数据传输不经过路由
- 查看 SELinux状态及关闭SELinux
- Linux中的find命令精华版(你会用到爱不释手)
- linux 下网关MAC的查看和配置arp命令
- 关于Linux系统调用,内核函数【转】
- Linux命令 进程状态命令 ps
- linux主机名变为bogon
- Linux-非结构化数据同步-Lsyncd介绍
- 1.2Linux文件系统
- Linux基础之变量设定规则
- 笔记本安装-Linux
- centos6
- 在centos中配置maven
- 第三周 构造一个简单的Linux系统
- Linux-非结构化数据同步-Linux下Lsyncd实现非结构化增量差异数据的同步4
- Linux-非结构化数据同步-Linux下Sersync+Rsync实现非结构化增量差异数据的实时同步3
- Linux-非结构化数据同步-Linux下Rsync+Rsync实现非结构化增量差异数据的同步2
- zabbix自动监控Linux端口 , 自动和手动监控windows端口 ,zabbix自动监控windows服务