Faac 编码实时pcm流到aac流 并用mp4v2打包成mp4文件

来源:互联网 发布:郑淳元秋意浓 知乎 编辑:程序博客网 时间:2024/05/16 07:02

 

由于项目需要,   需要将g711实时音频流,转码成aac流,  最终生成MP4文件保存,

 

网上搜索了一番,  最后采用如下的方法

 

1,  采用g711库相关函数, 先将g711音频流,解码成pcm数据,  

2,采用faac库, 将解码后的pcm数据,编码成aac 数据

3,采用mp4v2 将aac数据打包成mp4文件

 

 

网上下载了,开源的g711代码,和mp4v2-2.0.0

g711解码pcm  没什么好说的,很简单,

 

        BYTEszPcmBuff[PCM_BUFFER_SIZE] = {0};//1024

        intnPcmLen = g711a_decode( (short*)szPcmBuff, pBufferG711, nG711Len );

 

因为传送过来的g711音频流buf大小是 160个字节(nG711Len),  解码后的pcm大小为320所以定义的

PCM_BUFFER_SIZE= 320

 

关于AAC音频格式的理论知识参考以下这篇文章

AAC音频格式分析与解码

关于使用FAAC编码PCM数据为AAC,参考以下两篇文章

音频编解码·实战篇(1)PCM转至AAC(AAC编码)

Faac编码实时pcm流到aac

我直接拷贝过来了一部分

 

 

首先调用   faacEncHandlehEncode r= faacEncOpen(samplerate,channels,& samplesInput,&maxBytesOutput);

1.打开aac编码引擎,创建aac编码句柄。

参数 samplerate 为要编码的音频pcm流的采样率,channels为要编码的音频pcm流的的频道数(原有的例子程序是从wav文件中读出这些信息),sampleInput在编码时要用到,意思是每次要编码的采样数,参数maxBytesOutput为编码时输出地最大字节数。

 

2.然后在设置一些编码参数,如

int version=MPEG4;   //设置版本,录制MP4文件时要用MPEG4

intobjecttype=LOW;    //编码类型

intmidside=1;          //M/S编码

intusetns=DEFAULT_TNS;   //瞬时噪声定形(temporalnoise shaping,TNS)滤波器

intshortctl=SHORTCTL_NORMAL;

intinputformat=FAAC_INPUT_16BIT;  //输入数据类型

intoutputformat=RAW_STREAM; //录制MP4文件时,要用raw流。检验编码是否正确时可设

                                                          //置为adts传输流,把aac 流写入.aac文件中,如编码正确

                                                         //用千千静听就可以播放。

其他的参数可根据例子程序设置。

设置完参数后就调用faacEncSetConfiguration(hEncoder,aacFormat)设置编码参数。

3.如编码完的aac流要写入MP4文件时,要调用

faacEncGetDecoderSpecificInfo(hEncoder,&(ASC),&(ASCLength));//得到解码信息

                                                                                                                        //(mpeg4ip mp4 录制使用)

此函数支持MPEG4版本,得到的ASC 和ACSLength 数据在录制MP4(mpegip库)文件时用。

 

4.然后就是编码了,每次从实时的pcm音频队列中读出samplesInput* channels*(量化位数/8),

字节数的pcm数据。然后再把得到pcm流转变一下存储位数,

 

====================================================

 

这里补充说明一下,。

 

这里我用采样率为8000 单通道, 位深16 的音频为例

nSampleRate = 8000; 

nChannal = 1;

m_nBitsPerSample = 16;

 

调用  faacEncOpen(nSampleRate, nChannal, &m_nInputSamples, &m_nMaxOutputBytes);

之后, 得到m_nInputSamples=1024; m_nMaxOutputBytes = 768;

 

计算得出 m_nMaxInputBytes = m_nInputSamples*bitsPerSample/8 ;

m_nMaxInputBytes  = 2048;

也就是说在调用 faacEncEncode进行编码的时候,每次要解码m_nMaxInputBytes的PCM数据,类似帧的概念, 解码一帧PCM数据 输出的aac数据最大为m_nMaxOutputBytes,  你只需申请最大为m_nMaxInputBytes 的输出内存(m_pOutAACBuffer),交给faacEncEncode 就行了

   intnRet =faacEncEncode(m_hEncoder, (int*)m_pbPCMBuffer,m_nInputSamples,m_pOutAACBuffer,m_nMaxOutputBytes);

 

根据faacEncEncode的返回值,从m_pOutAACBuffer中取出nRet个字节,就是编码后的aac数据,注意在调用faacEncEncode前几次返回值为0,不要惊讶, 这是因为FAAC内部有缓存Buff.

 

然后将从m_pOutAACBuffer中取出编码后的一帧数据,就可以调用mp4v2库的MP4WriteSample函数打包mp4文件了。

 

参考代码

bool Mp4Mutex::init( int nSampleRate, int nChannal, int bitsPerSample,char * pMp4File ){m_nSampleRate = nSampleRate;m_nAudioChannal = nChannal;m_nBitsPerSample = bitsPerSample;// init faacm_hEncoder = faacEncOpen( nSampleRate, nChannal, &m_nInputSamples, &m_nMaxOutputBytes);m_nMaxInputBytes=m_nInputSamples*bitsPerSample/8;m_pbPCMBuffer = new BYTE [m_nMaxInputBytes];m_pOutAACBuffer = new BYTE [m_nMaxOutputBytes];m_pTempBuffer = new BYTE [TEMP_BUFFER_SIZE];memset(m_pTempBuffer, 0 , TEMP_BUFFER_SIZE);// Get current encoding configurationfaacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_hEncoder);if( !pConfiguration ){printf("GetCurrentConfiguration error!\n");return false;}//设置版本,录制MP4文件时要用MPEG4pConfiguration->version = MPEG4 ;pConfiguration->aacObjectType = LOW; //LC编码//输入数据类型pConfiguration->inputFormat = FAAC_INPUT_16BIT;// outputFormat (0 = Raw; 1 = ADTS)// 录制MP4文件时,要用raw流。检验编码是否正确时可设置为 adts传输流,pConfiguration->outputFormat= 1;//瞬时噪声定形(temporal noise shaping,TNS)滤波器pConfiguration->shortctl = SHORTCTL_NORMAL;pConfiguration->useTns=true;//pConfiguration->useLfe=false;pConfiguration->quantqual=100;pConfiguration->bandWidth=0;pConfiguration->bitRate=0;//  Set encoding configurationfaacEncSetConfiguration( m_hEncoder, pConfiguration);return true;}


编码

void Mp4Mutex::StartWriteMp4(unsigned char * pBufferG711,int nG711Len){if ( G711_BUFFER_SIZE < nG711Len ){}BYTE szPcmBuff[PCM_BUFFER_SIZE] = {0};//1024int nPcmLen = g711a_decode( (short*)szPcmBuff, pBufferG711, nG711Len );memcpy(m_pTempBuffer+m_nTempPos, szPcmBuff ,nPcmLen ) ;m_nTempPos += nPcmLen;if ( m_nTempPos < m_nMaxInputBytes ){return ;}memcpy(m_pbPCMBuffer, m_pTempBuffer ,m_nMaxInputBytes ) ;char szTemp[2048]={0};int nLeft = m_nTempPos-m_nMaxInputBytes;memcpy( szTemp, (m_pTempBuffer+m_nMaxInputBytes), nLeft );memset(m_pTempBuffer, 0, TEMP_BUFFER_SIZE );memcpy( m_pTempBuffer, szTemp, nLeft );m_nTempPos -= m_nMaxInputBytes ;int nRet = faacEncEncode(m_hEncoder, (int*)m_pbPCMBuffer, m_nInputSamples, m_pOutAACBuffer, m_nMaxOutputBytes );if ( nRet <= 0 ){return ;}MP4WriteSample( m_Mp4File, m_AudioTrackId, (BYTE*)&m_pOutAACBuffer[7], nRet-7 , 1024, 0, true);}


这里上传了我用来测试的一个工程,一个例子可以下载

http://download.csdn.net/detail/machh/8101485

 

 

 

 

 

扫描下方二维码。关注 【音视频开发训练营】 获取更多有价值的技术文章

 

 

 


0 0