美文网首页
使用libfaac进行音频编码

使用libfaac进行音频编码

作者: 吾心傲翔 | 来源:发表于2019-01-26 18:02 被阅读0次

使用FAAC编码PCM为AAC

关于FAAC

FAAC是一个MPEG-4和MPEG-2的AAC编码器,其特性是:可移植性好,快速,支持LC/Main/LTP,通过Dream支持DRM,代码小相对于FFMPEG的AAC转码,FAAC实在是微乎其微,而且可以直接把代码加到工程里面编译,也可使用静态库,而没有巨大的动态库的烦恼。

下载安装

直接按照官方文档所示,编译静态库以供我们程序使用。(我没这么做,个中曲折错误不细数)把FAAC的代码抠出来,直接加到我们的工程中去,或者抠出来编译一个静态库,简单暴力有效,需要的代码是libfaac和include两个目录下的所有文件(不包括子目录文件)。 目录文件列表如下所示:

aacquant.c

aacquant.h

backpred.c

backpred.h

bitstream.c

bitstream.h

channels.c

channels.h

coder.h

faac.h

faaccfg.h

fft.c

fft.h

filtbank.c

filtbank.h

frame.c

frame.h

huffman.c

huffman.h

hufftab.h

ltp.c

ltp.h

midside.c

midside.h

psych.h

psychkni.c

tns.c

tns.h

util.c

util.h

version.h

强烈推荐使用第二种方法

主要的函数介绍

faacEncHandle FAACAPI faacEncOpen(unsigned longsampleRate,

    unsigned intnumChannels,

    unsigned long*inputSamples,

    unsigned long*maxOutputBytes);

//  描述 : 打开并初始化编码器

//  sampleRate : 编码输入信息的采样率

//  numChannels : 编码输入信息的通道数量,1-单声道 2-立体声

//  inputSamples : 编码后的数据长度

//  maxOutputBytes : 编码后的信息最大长度

intFAACAPI faacEncClose(faacEncHandle hEncoder);

//  描述:关闭编码器

//  hEncoder : faacEncOpen返回的编码器句柄

faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder);

//  描述 :获取当前编码器的配置信息

//  hEncoder : faacEncOpen返回的编码器句柄

intFAACAPI faacEncSetConfiguration(faacEncHandle hEncoder, faacEncConfigurationPtr config);

//  描述 : 配置解码器的参数

//  hEncoder : faacEncOpen返回的编码器句柄

//  config : 编码器的配置信息

intFAACAPI faacEncEncode(faacEncHandle hEncoder,

int32_t * inputBuffer,

unsigned intsamplesInput,

unsigned char*outputBuffer,

unsigned intbufferSize);

//  描述 : 编码一桢信息

//  hEncoder : faacEncOpen返回的编码器句柄

//  inputBuffer : 输入信息缓冲区

//  samplesInput : faacEncOpen编码后的数据长度,即缓冲区长度

//  outputBuffer : 编码后输出信息缓冲区

//  bufferSize : 输出信息长度

intFAACAPI faacEncGetVersion(char**faac_id_string, char**faac_copyright_string);

//  描述 : 获取FAAC的版本信息,用以参考作用,非必须API

//  faac_id_string : faac的版本号

//  faac_copyright_string : 版权信息

代码示例

代码的工作流程是:

打开输入输出文件使用faacEncOpen打开编码器引擎使用faacEncGetCurrentConfiguratio获取编码器配置配置编码器参数使用faacEncSetConfiguration设置编码器配置读取一桢输入数据使用faacEncEncode编码帧数据写入编码数据到输出文件使用faacEncClose关闭编码引擎

//  PCM to ACC

#include "faac.h"

#include <stdio.h>

#include <stdlib.h>

int main()

{

    // 定义别名

    typedef unsigned charBYTE;

    unsigned longnSampleRate = 44100;

    unsigned intnChannels = 2;

    unsigned intnPCMBitSize = 16;

    unsigned longnInputSamples = 0;

    unsigned longnMaxOutputBytes = 0;

    faacEncHandle  hEncoder = {0};

    // 设置输入输出文件

    FILE* fpIn = fopen("test.pcm", "rb");

    FILE* fpOut = fopen("test.aac", "wb");

    if(fpIn==NULL || fpOut==NULL){

        printf("打开文件失败!\n");

        return-1;

    }

    // 打开faac编码器引擎

    hEncoder = faacEncOpen(nSampleRate, nChannels, &nInputSamples, &nMaxOutputBytes);

    if(hEncoder == NULL){

        printf("打开faac编码器引擎失败!\n");

        return-1;

    }

    // 分配内存信息

    intnPCMBufferSize = nInputSamples*nPCMBitSize/8;

    BYTE*  pbPCMBuffer = newBYTE[nPCMBufferSize];

    BYTE*  pbAACBuffer = newBYTE[nMaxOutputBytes];

    // 获取当前编码器信息

    faacEncConfigurationPtr pConfiguration = {0};

    pConfiguration = faacEncGetCurrentConfiguration(hEncoder);

    // 设置编码配置信息

    /*

        PCM Sample Input Format

        0  FAAC_INPUT_NULL        invalid, signifies a misconfigured config

        1  FAAC_INPUT_16BIT        native endian 16bit

        2  FAAC_INPUT_24BIT        native endian 24bit in 24 bits      (not implemented)

        3  FAAC_INPUT_32BIT        native endian 24bit in 32 bits      (DEFAULT)

        4  FAAC_INPUT_FLOAT        32bit floating point

    */

    pConfiguration->inputFormat = FAAC_INPUT_16BIT;

    // 0 = Raw; 1 = ADTS

    pConfiguration->outputFormat = 1;

    // AAC object types

    //#define MAIN 1

    //#define LOW  2

    //#define SSR  3

    //#define LTP  4

    pConfiguration->aacObjectType = LOW;

    pConfiguration->allowMidside = 0;

    pConfiguration->useLfe = 0;

    pConfiguration->bitRate = 48000;

    pConfiguration->bandWidth = 32000;

    faacEncSetConfiguration(hEncoder, pConfiguration);

    size_t nRet = 0;

    printf("数据转换中:        ");

    inti = 0;

    while( (nRet = fread(pbPCMBuffer, 1, nPCMBufferSize, fpIn)) > 0){

        printf("\b\b\b\b\b\b\b\b%-8d", ++i);

        nInputSamples = nRet / (nPCMBitSize/8);

        // 编码

        nRet = faacEncEncode(hEncoder, (int*) pbPCMBuffer, nInputSamples, pbAACBuffer, nMaxOutputBytes);

        // 写入转码后的数据

        fwrite(pbAACBuffer, 1, nRet, fpOut);

    }

    faacEncClose(hEncoder);

    fclose(fpOut);

    fclose(fpIn);

    delete[] pbAACBuffer;

    delete[] pbPCMBuffer;

    return0;

}

编码器的参数设置,

打开FAAC编码器

m_faacHandle = faacEncOpen(isamplerate, ichannels, &m_uSampleInput, &m_uOutputBytes);

if( 0 == m_faacHandle )

return false ;

faacEncConfigurationPtr faacCfg;

faacCfg = faacEncGetCurrentConfiguration(m_faacHandle);

if (faacCfg->version != FAAC_CFG_VERSION){

return false ;

}

//* 设置配置参数

faacCfg->aacObjectType = LOW; //LC编码

faacCfg->mpegVersion = MPEG4;//

faacCfg->useTns = 1 ;//时域噪音控制,大概就是消爆音

faacCfg->allowMidside =0 ;//

faacCfg->bitRate = m_nBitRate/m_uChannelNums;

faacCfg->bandWidth = 0 ; //频宽

faacCfg->outputFormat = isADTS; //输出是否包含ADTS头

faacCfg->inputFormat = FAAC_INPUT_16BIT;

//faacCfg->shortctl = 0 ;

faacCfg->quantqual = 50 ;

//* 获取解码信息.

//unsigned char* ucBuffer = NULL;

//unsigned long ulDecoderSpecificInfoSize;

//faacEncGetDecoderSpecificInfo(m_faacHandle, &ucBuffer, &ulDecoderSpecificInfoSize);

if (!faacEncSetConfiguration(m_faacHandle, faacCfg)){

return false ;

}

m_uSampleInput这个参数要注意,需要在编码时使用。是faac所使用的音频样片数量

随后就可以解码了

int iBytesWritten = faacEncEncode(m_faacHandle, (int32_t*)input, m_uSampleInput , output, outlen );

判断下iBytesWritten初始编码的几帧数据会返回0,0是数据被缓冲,并不是错误。

解码相对编码更简单。

但是遇到个问题,就是编码单声道的数据,解码会返回双声道,这对打开播放设备播放时造成了一定的

困扰。因为前期是将音频编码参数优先发送出来,接收端收到参数后会打开播放设备,现在得在数据解码后再打开

播放设备。

我的程序是根据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 charbufi[8];

while(i

{

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);就行了

相关文章

网友评论

      本文标题:使用libfaac进行音频编码

      本文链接:https://www.haomeiwen.com/subject/jagijqtx.html