音视频学习记录二利用faac库实现PCM转AAC(录音并编码)

前言,我的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);

以上就是我的录音+编码模块的编码主体,有错误欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值