• AAC是一种音频压缩技术,是有损压缩(线性pcm是无损)
  • AAC压缩比通常为18:1,也有资料说为20:1,远胜mp3
  • AAC可以支持多达48个音轨,15个低频(LFE)音轨,5.1多声道支持;
  • 更高的采样率,最高可达96kHz,音频CD为44.1kHz;
  • 更高的采样精度,支持8bit、16bit、24bit、32bit,音频CD为16bit;
  • 以及有多种语言的兼容能力,更高的解码效率,
  • 一般来说,AAC可以在比MP3文件缩小30%的前提下提供更好的音质AAC规格与编解码器

目前听到用的比较多的应该是 LC-AAC、HE-AAC、Main(主规格)、SSR(可变采样率)等规格

常见的AAC编解码有: NERO AAC, QuikTime AAC, FAAC

format

AAC编码的扩展名有: .aac .mp4 aac:使用ADTS容器(ADIF不常见,必须从开头开始解码,用在磁盘文件中),也是faac默认的封装格式 mp4:使用3gpp(MPEG4-Part14)进行封装,Nero AAC 编码器使用该封装格式 m4a:苹果公司使用的封装格式,等同于 MP4封装格式,可以直接改动扩展名

FAAC

faac是免费的编解码器它包括:faac(encode),faad2(decode) 支持 LC, Main, HE 等解码规格 支持 ADTS AAC, raw AAC, MP4 等文件格式 对应的两个库接口是 libfaac,libfaad FAAD 解码中最小的音频流大小为768B,而8K单声道的音频流为384B 解码中一次最少也应该为768B所以某些情况下可能要求拼凑

LC-AAC

Low Complexity,低复杂度AAC规格

这种规格在"中等码率"(96kbps-192kbps)的编码效率以及音质方面,都能找到平衡点。

HE-AAC

high efficiency,高效,HE 使用了 SBR 技术和 PS 技术(V2):

encoding

// 获取FAAC版本信息
char *faac_id_string;
char *faac_copyright_string
if (faacEncGetVersion(&faac_id_string, &faac_copyright_string) == FAAC_CFG_VERSION)
    fprintf(stderr, "FAAC Version: %s\n\n", faac_id_string);
else {
    fprintf(stderr, __FILE__"(%d): wrong lib faac version", __LINE__);
    return 1;
}

// 打开FAAC编码器
unsigned long samplesInput, maxBytesOutput;
faacEncHandle hEncoder = faacEncOpen(44100, 1, &samplesInput, &maxBytesOutput);

// 设置FAAC编码器属性
faacEncConfiguration* myFormat = faacEncGetCurrentConfiguration(hEncoder);
myFormat.aacObjectType = LOW;
myFormat.mpegVersion = MPEG2;
myFormat.allowMidside = 0;
myFormat.useLfe = 0
myFormat.useTns = 0;
myFormat.shortctrl = SHORTCTL_NORMAL;
myFormat.bitRate = 44100 / 1; // bitrate/channels
myFormat.quantqual = 0;
myFormat.outputFormat = 1; // 0,RAW; 1,ADTS(音频数据传送流)
myFormat.inputFormat = 1; // FAAC_INPUT_16BIT
if (!faacEncSetConfiguration(hEncoder, myFormat)) {
    fprintf(stderr, "Unsupported output format!\n");
    faacEncClose(hEncoder);
}

// 真实的编解码
unsigned char* pOutBuf = (unsigned char*) malloc(maxBytesOutput *sizeof( unsigned char ));
while (1) {
    int bytesEncoded;
    memset(pOutBuf, 0, maxBytesOutput);
    bytesEncoded = faacEncEncode(hEncoder,(short*)pInputBuf, samplesInput, pOutBuf, maxBytesOutput);
    if (!bytesEncoded || !samplesInput)
        break;
    if (bytesEncoded < 0) {
        fprintf(stderr, "faacEncEncode() failed\n");
        break;
    }
    /* write bitstream to aac file */
    fwrite(bitbuf, 1, bytesEncoded, outfile);
}

// 关闭编码器
faacEncClose(hEncoder);

decoding

unsigned long cap = faacDecGetCapabilities();
if (cap & FIXED_POINT_CAP) fprintf(stderr, "error");
faacDecHandle hAacDec = faacDecOpen();
faacDecConfiguration* pAacCfg = faacGetCurrentConfiguration(hAacDec);
faacDecSetConfiguration(hAacDec, pAacCfg);

// 初始化
unsigned char* pInitBuf = (unsigned char*)malloc(pInitBuf, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);

// 填进去一些压缩的音频数据调用
unsigned long sampleRate;
unsigned char channels;
int temp = faacDecInit(hAacDec, pInitBuf, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, &sampleRate, &channels);
if (temp < 0) {
    // faacDecClose(hAacDec);
}

unsigned char* pInputBuf = (unsigned char*)malloc(pInputBuf, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);
faacDecFrameInfo frameInfo;
do {
    /** 向pInputBuf放入 src Data 解码 **/
    void* sample_buffer = faacDecDecode(hDecoder, &frameInfo, pInputBuf, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);
    if ((frameInfo.error == 0) && (frameInfo.samples > 0)) {
        // fwrite返回实际写入的字节数当出错时文件指针就混乱了
        fwrite(sample_buffer, 1, frameInfo.samples, FILE*);
    }
    if (frameInfo.error > 0)
       fprintf(stderr, "warning: %s", faacDecGetErrorMessage(frameInfo.error));
} while (sample_buffer != NULL);

faacDecClose(hAacDec);