前言,我的pcm数据来自硬件录音,得到record_data,以及数据大小record_data_size,后续采用faac库进行编码,存储为aac格式文件。(也可以直接读取pcm文件进行编码,更简单,但是我需要的是录音+编码的组合模块)
0.必备的设置参数如下:
//以下参数可以理解为告诉编码器PCM文件的基本参数
unsigned long pcm_samplerate = 48000; // 采样率
unsigned int pcm_samplebits = 16; // 采样位数
unsigned int pcm_channels = 2;// 声道数
//这两个参数调用faacEncOpen函数时会写入值,不需要自己设置
unsigned long inputSample = 0; //编码器一次输入的样本数(非字节数)
unsigned long aac_outmax = 0; // 编码输出最大字节数(编码后的输出缓冲区的最大容量)
//这两个参数就是编码器输入输出缓冲区,需要提前malloc内存
unsigned char *pcm_inbuf = NULL; // PCM 输入数据缓冲区
unsigned char *aac_encout = NULL; // AAC 编码输出数据缓冲区
//调用faacEncOpen获取编码器句柄
faacEncHandle pFaacEncHandle; //faac编码器句柄
//调用faacEncGetCurrentConfiguration获取当前设置
faacEncConfigurationPtr pFaacEncConf; //faac设置类结构体
1.AAC编码 1/4:打开编码器,分配输入输出缓冲区内存
//打开编码器参数介绍
faacEncHandle FAACAPI faacEncOpen(
unsigned long sampleRate, // pcm音频采样率,8k,16k,44100等
unsigned int numChannels, // pcm音频通道,mono = 1 / stereo = 2
unsigned long *inputSamples, // 一次输入的样本数(非字节数)
unsigned long *maxOutputBytes);// 输出aac缓冲区的最大size (单位字节)
//调用会获取当前句柄,并写入inputSample,maxOutputBytes的值
pFaacEncHandle = faacEncOpen(pcm_samplerate, pcm_channels, &inputSample, &aac_outmax);
// 根据上面打开编码器传出的参数分配对应大小的缓存
int pcmbuffer_size = 0; //编码时一次传入的PCM样本缓存大小(注意此单位为字节)
pcmbuffer_size = inputSample * pcm_samplebits / 8;//(样本数*位深/8)
pcm_inbuf = (unsigned char *)malloc(pcmbuffer_size);//输入缓存区大小
aac_encout = (unsigned char *)malloc(aac_outmax);//输出缓存区大小
2.AAC编码 2/4:设置编码器配置
注意在这一步其实是分为三个步骤的:
设置编码器配置 a/c: 获取当前编码器配置
//传入编码器句柄,获取当前编码器配置
pFaacEncConf = faacEncGetCurrentConfiguration(pFaacEncHandle);
设置编码器配置 b/c: 根据需要修改编码器配置
这部分详细的更改建议查看源码的结构体,然后改成自己想要的参数,可以理解成,这是编码参数的设置,也就是你想要什么样的文件,你就改成什么样的参数,告诉编码器你的需求
//copy this struct from headfile
typedef struct faacEncConfiguration{
/* config version - 配置版本,可以默认不设置*/
int version;
/* library version - 库版本,可以默认不设置*/
char *name;
/* copyright string - 版权,可以默认不设置*/
char *copyright;
/* MPEG version, 2 or 4 - MPEG版本,MPEG2 or MPEG4*/
unsigned int mpegVersion;
/* AAC object type - AAC对象类型,详细见补充说明1,取值:1-MAIN 2-LOW 3-SSR 4-LTP*/
unsigned int aacObjectType;
/* Allow mid/side coding - 是否允许mid/side coding, 详细见补充说明2,取值:0-NO 1-YES*/
unsigned int allowMidside;
/* Use one of the channels as LFE channel - 是否允许一个通道为低频通道,取值:0-NO 1-YES*/
/* LFE(low-frequencyeffects) */
unsigned int useLfe;
/* Use Temporal Noise Shaping - 瞬时噪声定形(temporal noise shaping,TNS)滤波器,取值:0-NO 1-YES*/
unsigned int useTns;
/* bitrate / channel of AAC file - AAC文件的bitrate / channel 取值:0和48000都可以,暂时不清楚这个参数作用*/
unsigned long bitRate;
/* AAC file frequency bandwidth - 频宽 取值:0, 32000,64000都可以,暂时不清楚参数作用*/
unsigned int bandWidth;
/* Quantizer quality - 编码质量,取值:efault=100 LOWER<100 HIGHER>100*/
/* 默认100,值越大音质越高 */
unsigned long quantqual;
/* Bitstream output format (取值:0 = Raw; 1 = ADTS) - 输出数据类型(是否包包含adts头),录制MP4文件时,要用raw流,ADTS详细见补充说明3*/
unsigned int outputFormat;
/* psychoacoustic model list*/
psymodellist_t *psymodellist;
/* selected index in psymodellist*/
unsigned int psymodelidx;
/*
PCM Sample Input Format - 输入pcm数据类型
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
*/
unsigned int inputFormat;
/* block type enforcing -
* (SHORTCTL_NORMAL/SHORTCTL_NOSHORT/SHORTCTL_NOLONG)
*/
int shortctl;
/*
Channel Remapping
Default 0, 1, 2, 3 ... 63 (64 is MAX_CHANNELS in coder.h)
WAVE 4.0 2, 0, 1, 3
WAVE 5.0 2, 0, 1, 3, 4
WAVE 5.1 2, 0, 1, 4, 5, 3
AIFF 5.1 2, 0, 3, 1, 4, 5
*/
int channel_map[64];
} faacEncConfiguration, *faacEncConfigurationPtr;
参数设置示例:
第一步:
faacEncConfigurationPtr pConfiguration;
pConfiguration->outputFormat = 1;
pConfiguration->aacObjectType = LOW;
pConfiguration->bitRate = 48000; // or 0
pConfiguration->bandWidth = 64000; //or 0 or 32000
pConfiguration->inputFormat = FAAC_INPUT_16BIT;
/*下面可以选择设置*/
pConfiguration->allowMidside = 1;
pConfiguration->useLfe = 0;
pConfiguration->useTns = 0;
pConfiguration->quantqual = 100;
pConfiguration->outputFormat = 1;
pConfiguration->shortctl = SHORTCTL_NORMAL;
设置编码器配置 c/c: 重新设置编码器的配置信息
//这个函数就是把你重新设置好的参数(存放在这个pFaacEncConf结构体),喂给当前的编码器句柄
faacEncSetConfiguration(pFaacEncHandle, pFaacEncConf);
3.AAC编码 3/4:读取录音区的PCM数据->重新编码成AAC格式->写入aac文件
这里先介绍用到的faacEncEncode编码api,注意每一个参数对用的调用,尤其是unsigned int samplesInput,此参数在第一步调用faacEncOpen时获得,指的是每一次输入的样本数,我在前期一直没搞懂这个参数的含义,出现了很多错误
int FAACAPI faacEncEncode(
faacEncHandle hEncoder, //编码器句柄 对应pFaacEncHandle
int32_t * inputBuffer, //pcm输入buffer 对应pcm_inbuf
unsigned int samplesInput, //一次输入的样本数,对应sinputSample
unsigned char *outputBuffer, //AAC输出buffer, 对应aac_encout
unsigned int bufferSize); //输出最大长度 对应aac_outmax
函数调用成功会返回实际AAC数据大小,从aac_encout中读出即可。
下面介绍基于我自己情况的编码主体,仅供参考
其中需要注意的是,前几次faacEncEncode的返回值会=0,是很正常的情况,可能是读取慢等原因,所以不要直接做>0的判断。
/* AAC编码 3/4:循环操作:读取录音区的PCM数据->重新编码成AAC格式->写入aac文件*/
size_t offset = 0; // 用来追踪已经处理的数据字节数
size_t nRet = 0; // 记录每次读取的字节数
size_t bytesRead = aac_info->record_data_size;
while (offset < bytesRead) {
size_t bytesToRead = (bytesRead - offset) < pcmbuffer_size ? (bytesRead - offset) : pcmbuffer_size;
memcpy(pcm_inbuf, record_data + offset, bytesToRead);
offset += bytesToRead;// 更新已读取的字节数
//ret为编码后数据长度
int ret = faacEncEncode(aac_info->pFaacEncHandle, (int32_t *)pcm_inbuf, inputSample, aac_encout, aac_outmax);
//ret为0时不代表编码失败,而是编码速度较慢,导致缓存还未完全flush,可用一个循环继续调用编码接口,当 ret>0 时表示编码成功,且返回值为编码后数据长度
while (ret == 0)
{
ret = faacEncEncode(aac_info->pFaacEncHandle, (int32_t *)pcm_inbuf, inputSample, aac_encout, aac_outmax);
}
if (ret > 0)
{
//写入文件
size_t writtenBytes = fwrite(aac_encout, 1, ret, fpEnc);
if (writtenBytes != (size_t)ret) {
err_printf("(loop)Error writing to file.\n");
return -1;
}
}
// 记录每次读取的字节数
nRet = bytesToRead;
// 如果读取的字节数为0,表示数据已经全部读取完
if (nRet == 0) {
break;
}
}
/* 释放内存 */
free(pcm_inbuf);
free(aac_encout);
4.AAC编码 4/4:关闭编码器
//传入当前编码器句柄关闭
faacEncClose(pFaacEncHandle);
以上就是我的录音+编码模块的编码主体,有错误欢迎指正。
2106

被折叠的 条评论
为什么被折叠?



