美文网首页音视频
编码PCM数据到AAC,详解(使用faac)

编码PCM数据到AAC,详解(使用faac)

作者: 木容虾 | 来源:发表于2018-03-08 15:50 被阅读0次

    关于AAC的编码我找了相当多的相关资料,最开始是打算使用雷霄骅同学所贡献的ffmpeg方式来做,一开始本来通过ffmpeg进行视频解码时已经使用了最新的接口,最后在参照雷神博客时发现了暗坑,雷神用的库版本支持aac编码格式为AV_SAMPLE_FMT_S16,但是新版已经只支持AV_SAMPLE_FMT_FLTP,如果参照雷神的逻辑来使用,基本上没有办法编码成功。于是只能放弃ffmpeg自带aac编码器,使用比较常用的faac来进行编码。

    faac官网链接:http://www.audiocoding.com/faac.html
    官网下载有时会有些问题,可以下载我的faac1.28 链接:https://pan.baidu.com/s/1xqvyZotTmPPB0D5ica8MyA 密码:xgza

    下载解压后进入libfaac,用vs打开libfaac_dll_drm.sln重新生成release版本,就可以在ReleaseDLL文件里找到dll和lib文件。将库加到工程里后就可以开始编码了。

    首先声明编码所需类和变量

        unsigned long sampleRate = 44100;  //编码采样率
        unsigned int numChannels = 2;         //编码声道数
        unsigned long inputSample = 0;        //输入样本大小,在打开编码器时会得到此值
        unsigned long maxOutputBytes = 0;  //最大输出,编码后的输出数据大小不会高于这个值,也是打开编码器时获得
        unsigned int    mPCMBitSize = 16;    //pcm位深,用于计算一帧pcm大小
    
        int mPCMBufferSize = 0;    //一帧PCM缓存大小
        int mCountSize = 0;           //计算缓存大小
        char* mPCMBuffer;           //PCM缓存
    
        faacEncHandle encoder;    //faac编码器句柄
        faacEncConfigurationPtr config;   //faac设置类
    

    编码准备第一步
    打开编码器:

    @param sampleRate :编码采样率
    @param numChannels:声道数
    @param inputSample:  输入样本大小
    @param maxOutputBytes: 输出数据最大值
    @return encoder:编码器句柄
    encoder = faacEncOpen(sampleRate, numChannels, &inputSample, &maxOutputBytes);
    

    第二步
    对编码器进行设置;

        config = faacEncGetCurrentConfiguration(encoder);   //获取当前编码器的设置句柄  
        config->aacObjectType = LOW;    //设置AAC类型
        config->useLfe = 0;    //是否允许一个声道为低频通道
        config->useTns = 1;  //是否使用瞬时噪声定形滤波器(具体作用不是很清楚)
        config->allowMidside = 0;  //是否允许midSide coding (在MPEG-2 AAC 系统中,M/S(Mid/Side) Stereo coding被提供在多声道信号中,每个声道对(channel pair)的组合,也就是每个通道对,是对称地排列在人耳听觉的左右两边,其方式简单,且对位串不会引起较显著的负担。 一般其在左右声道数据相似度大时常被用到,并需记载每一频带的四种能量临界组合,分别为左、右、左右声道音频合并(L+R)及相减(L-R)的两种新的能量。一般,若所转换的Sid声道的能量较小时,M/S Stereo coding 可以节省此通道的位数,而将多余的位应用于另一个所转换的声道,即Mid 声道,进而可提高此编码效率。)
        config->outputFormat =1;  // RAW_STREAM = 0, ADTS_STREAM=1  (ADTS可以实现单帧单独解码,raw由于缺少头无法单帧解码,因此无法做实时传输)
        config->bitRate =48000;  //设置比特率
        config->inputFormat = FAAC_INPUT_16BIT;  //设置输入PCM格式
        faacEncSetConfiguration(encoder, config);   //应用设置
    

    第三步
    计算PCM缓存所需大小以分配相应空间

        mPCMBufferSize = inputSample * mPCMBitSize / 8;
        mPCMBuffer = new char[mPCMBufferSize];
    

    最终,开始编码了!!!

    @param pcmData :pcm数据
    @param size: pcm数据长度
    startEncode(char* pcmData,int size)
    {
           //判断pcm缓存区是否已满,如果没有,继续添加下一次数据,用mCountSize进行记数
        if (mCountSize<mPCMBufferSize)
        {
            memcpy(mPCMBuffer +mCountSize,pcmData,size);
            mCountSize += size;
        }
        else
        {
            mCountSize = 0;   //缓存区已满,重置记数
            unsigned char* aacData = new unsigned char[maxOutputBytes];   //编码后输出数据(也就是AAC数据)存放位置
            
            //开始编码,encoder为编码器句柄,mPCMBuffer为PCM数据,inputSample为打开编码器时得到的输入样本数据
            //aacData为编码后数据存放位置,maxOutputBytes为编码后最大输出字节数,ret为编码后数据长度
            int ret = faacEncEncode(encoder, (int32_t *)mPCMBuffer, inputSample, 
                aacData, maxOutputBytes);  
            //ret为0时不代表编码失败,而是编码速度较慢,导致缓存还未完全flush,可用一个循环继续调用编码接口,当 ret>0 时表示编码成功,且返回值为编码后数据长度
               while (ret == 0)
            {
                ret = faacEncEncode(encoder, (int32_t *)mPCMBuffer, inputSample, aacData, maxOutputBytes);
            }
    
                if (ret > 0)
            {
                TRACE(_T("encode voice success !\n"));
                //到这里已经编码成功,aacData为编码后数据
                //我是写入一个自定义AACData结构体并放入队列进行处理,这里的aacData可按情况自行处理(如直接写入文件)
                AACData* aac = new AACData();
                aac->aacData = aacData;
                aac->size = ret;
                m_aacFrameQueue->push(aac);
            }
            else
            {
                TRACE(_T("encode failed!!\n"));
            }
        }
    }
    

    一开始在编码这里卡住很久,因为在采集pcm数据的过程中,并非每次都是完整一帧,也不知道编码器一次究竟需要多大的pcm数据样本,后来通过一通搜刮,计算出pcm缓存大小,再送入编码器也就成功了

    相关文章

      网友评论

        本文标题:编码PCM数据到AAC,详解(使用faac)

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