由于项目需要, 需要将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 faac m_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 configuration faacEncConfigurationPtr pConfiguration = faacEncGetCurrentConfiguration(m_hEncoder); if( !pConfiguration ) { printf("GetCurrentConfiguration error!\n"); return false; } //设置版本,录制MP4文件时要用MPEG4 pConfiguration->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 configuration faacEncSetConfiguration( m_hEncoder, pConfiguration); return true; }
编码
void Mp4Mutex::StartWriteMp4(unsigned char * pBufferG711,int nG711Len) { if ( G711_BUFFER_SIZE < nG711Len ) { } BYTE szPcmBuff[PCM_BUFFER_SIZE] = {0};//1024 int 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
扫描下方二维码。关注 【音视频开发训练营】 获取更多有价值的技术文章