前言
最近在调试fdk-aac编解码,总结了一下需要注意的点,代码在公司内网懒得再敲了。本文介绍的是实时码流的编解码。有问题欢迎指出、讨论。
编译
1. fdk-aac开源代码下载:
2. 根据所使用的交叉编译器来设置cmake中的toolchain,例如我是在Hi3516上使用的,toolchain需要设置为hisiv300,就需要在下载的开源代码根目录下CMakeList.txt中添加命令:
# SET (CMAKE_C_COMPILER path) // path代指编译器路径
3. 执行cmake ./
4. 步骤3执行成功后会生成一个Makefile,终端下输入make开始编译
a) fdk-aac文件夹不可以放在共享目录中(我实在虚拟机中使用的,所以会有共享目录)
b) 编译成功后会生成libfdk-aac.so、libfdk-aac.so.2、libfdk-aac.so.2.0.2三个文件
5. 使用时需要将3个库都放到lib中
编码
1. 参考开源库中aac_aenc.c中的demo即可实现编码。
2. 需要注意的一点是,每次送入encoder的数据的size是有要求的。
AACENC_InfoStruct aac_info;
/* 中间省略了参数设置、初始化encoder的过程 */
/*
* input_size: 输入PCM数据的大小
* channels:通道数
* frameLength:每帧每个通道的采样点数
*/
int channels = 2; // 2:双通道
int input_size = channels * 2 * aac_info.frameLength;
3. 当然,如果你和我碰到一样的情况,采集的PCM数据大小和input_size不同,也可以通过加一个缓冲buffer来解决。每当采集到PCM数据,就将其存储到缓冲buffer中,当缓冲buffer中数据长度达到input_size时就取出input_size个字节进行编码。
RTP打包
打包编码后的aac数据这位博主写的很详细。
从零开始写一个RTSP服务器(五)RTP传输AAC_JT同学的博客-CSDN博客_rtp发送aac
解码
fdk-aac解码主要有两种模式:RAW模式和ADTS模式。
RAW模式
基本流程如下:
aacDecoder_Open();
aacDecoder_ConfigRaw();
loop{
aacDecoder_Fill();
aacDecoder_DecodeFrame();
}
aacDecoder_Close();
1. RAW模式需要在初始化decoder时,调用aacDecoder_ConfigRaw()传入AudioSpecInfo(ASC),这个结构体中存储着送入的raw数据的samplerate、channel等,送数据时需要去掉ADTS头。
2. 自己构建ASC数据可能会出现问题,建议在编码的时候就保存下来。在用fdk-aac编码时调用aacEncInfo()会获取到一个结构体AACENC_InfoStruct,该结构体中最后两个成员confBuf{64}、confSize就分别对应ASC和ASC的size。
ADTS模式
基本流程如下:
aacDecoder_Open();
loop{
/* 添加 增加adts头的代码 */
aacDecoder_Fill();
aacDecoder_DecodeFrame();
}
aacDecoder_Close();
1. ADTS模式初始化时不需要传入AudioSpecInfo(ASC),送数据时需要加上ADTS头。我编码时设置的是AAC_LC,采样率48K,双通道。参数不同的可以参考下面图片。
/* 添加ADTS头
* 一帧完整AAC数据 = ADTS头(7字节) + AAC源数据
*
* aac_frame
* aac_frame_size
*
*/
void addADTSHead(unsigned char *aac_frame, int aac_frame_size)
{
int profile = 2; // AAC_LC
int freqIdx = 3; // sampleRate: 48K
int chanCfg = 2; // channel: stero
aac_frame[0] = 0xFF;
aac_frame[1] = 0xF1;
aac_frame[2] = (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
aac_frame[3] = (((chanCfg & 3) << 6) + (aac_frame_size >> 11));
aac_frame[4] = ((aac_frame_size & 0x7FF) >> 3);
aac_frame[5] = (((aac_frame_size & 7) << 5) + 0x1F);
aac_frame[6] = 0xFC;
}