嵌入式linux:音频编解码PCM转至AAC

来源:互联网 发布:深圳市大数据研究院 编辑:程序博客网 时间:2024/06/05 08:09
  • 作者:柳大·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.gztar zxvf faac-1.28.tar.gzcd faac-1.28./configuremakesudo 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 __cplusplusextern "C" {#endifchar *strcasestr(const char *haystack, const char *needle);#ifdef __cplusplus}#endif

修改后:

#ifdef __cplusplusextern "C++" {#endifconst 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编码器,做编码前的准备

  1. 调用faacEncOpen开启FAAC编码器后,得到了单次输入样本数nInputSamples和输出数据最大字节数nMaxOutputBytes
  2. 根据nInputSamplesnMaxOutputBytes,分别为PCM数据和将要得到的AAC数据创建缓冲区;
  3. 调用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

  1. AudioCoding.com - FAAC
  2. Dogfoot – 재밌는 개발

-

转载请注明来自柳大的CSDN博客:blog.csdn.net/poechant

0 0
原创粉丝点击