前面几篇文章介绍了AAC的几种封装标准及libfdk-aac的一些使用细节,这篇文章就给出libfdk-aac编解码代码示例。
编码封装类CAACEncoder适用于RTP流媒体应用,设置的AAC编码规格为AAC-LD,封装格式为LATM,设置编码输入的采样点数为480(适用于采样率为48000),包复用个数为2(适用于采样周期为20ms)
编码接口 int EncodeFrame(unsigned char* pExpandedFrame,unsigned int len, unsigned char* pEncodedFrame)
len表示raw audio frame的长度,应该为480的整数倍
头文件
#ifndef FDK_AAC_ENCODER_H
#define FDK_AAC_ENCODER_H
#include
#include "libAACenc/include/aacenc_lib.h"
#define AAC_MAX_SAMPLE_CNT 480
class CAACEncoder
{
public:
CAACEncoder();
~CAACEncoder();
int Init();
int Start();
int Stop();
void SetCodecParameters(
int ChannelNum,
int AudioSampleRate,
int AudioBitrate,
int EncodeMode,
int FrameSize);
int EncodeFrame(unsigned char* pExpandedFrame,
unsigned int len,
unsigned char* pEncodedFrame);
int GetEncodedFrameSize()
{
int tmp = m_EncodedFrameSize;
m_EncodedFrameSize = 0;
return tmp;
};
void Destroy();
private:
int m_EncodedFrameSize;
//fdk-aac
HANDLE_AACENCODER m_AAChandle;
CHANNEL_MODE m_ChannelMode;
unsigned int m_iEncoderBufferSize;
//2->AAC-LC 5->HE-AAC 29->HE-AAC-v2 23->AAC-LD 39->AAC-ELD
int m_iEncodMode;
int m_iAudioSample;
int m_iAudioBitrate;
};
#endif
cpp文件
#include "AACEncoder.h"
CAACEncoder::CAACEncoder() :
m_AAChandle(NULL)
, m_ChannelMode(MODE_UNKNOWN)
, m_iEncodMode(2)
, m_iEncoderBufferSize(0)
, m_iAudioSample(0)
, m_iAudioBitrate(0)
, m_EncodedFrameSize(0)
{
}
CAACEncoder::~CAACEncoder()
{
Destroy();
}
void CAACEncoder::SetCodecParameters(int ChannelNum,
int AudioSampleRate,
int AudioBitrate,
int EncodeMode,
int FrameSize)
{
//音频声道数
if (1 == ChannelNum)
{//单声道
m_ChannelMode = MODE_1;
}
else if (2 == ChannelNum)
{//双声道
m_ChannelMode = MODE_2;
}
m_iEncodMode = EncodeMode;
m_iAudioSample = AudioSampleRate;
m_iAudioBitrate = AudioBitrate;
}
int CAACEncoder::EncodeFrame(unsigned char* pExpandedFrame,
unsigned int len,
unsigned char* pEncodedFrame)
{
unsigned char* pOutData = pEncodedFrame;
unsigned int iAlreadyConsumeBytes = 0;
unsigned char* pData = pExpandedFrame;
while (1)
{
void* pInputData[] = { (void*)(pData + iAlreadyConsumeBytes) };
void *pOutputData[] = { (void*)(pEncodedFrame + m_EncodedFrameSize) };
int inSize = (int)len;
//一个采样点占两个字节
int iSampleBytes = 2;
AACENC_BufDesc inBuf = { 0 };
AACENC_InArgs inArgs = { 0 };
//输入缓存的标识
int in_identifier = IN_AUDIO_DATA;
AACENC_ERROR err;
//采样点个数
inArgs.numInSamples = (len <= 0 ? -1 : inSize / 2);
inBuf.numBufs = 1;
inBuf.bufs = pInputData;
inBuf.bufferIdentifiers = &in_identifier;
inBuf.bufSizes = &inSize;
inBuf.bufElSizes = &iSampleBytes;
AACENC_BufDesc outBuf = { 0 };
AACENC_OutArgs outArgs = { 0 };
//输出缓存的标识
int out_identifier = OUT_BITSTREAM_DATA;
int outElemSize = 1;
outBuf.numBufs = 1;
outBuf.bufs = pOutputData;
outBuf.bufferIdentifiers = &out_identifier;
int OutBufSizes = m_iEncoderBufferSize;
outBuf.bufSizes = &OutBufSizes;
outBuf.bufElSizes = &outElemSize;
if ((err = aacEncEncode(m_AAChandle, &inBuf, &outBuf, &inArgs, &outArgs)) != AACENC_OK)
{
if (err == AACENC_ENCODE_EOF)
{
break;
}
return -1;
}
iAlreadyConsumeBytes = outArgs.numInSamples * 2;
m_EncodedFrameSize += outArgs.numOutBytes;
len -= iAlreadyConsumeBytes;
}
return 0;
}
int CAACEncoder::Init()
{
if (aacEncOpen(&m_AAChandle, 0, m_ChannelMode) != AACENC_OK)
{
return -1;
}
//设置编码规格 AAC-LD AOT值为23
if (aacEncoder_SetParam(m_AAChandle, AACENC_AOT, m_iEncodMode) != AACENC_OK)
{
return -1;
}
//设置采样率
if (aacEncoder_SetParam(m_AAChandle, AACENC_SAMPLERATE, m_iAudioSample) != AACENC_OK)
{
return -1;
}
//设置声道数
if (aacEncoder_SetParam(m_AAChandle, AACENC_CHANNELMODE, m_ChannelMode) != AACENC_OK)
{
return -1;
}
//设置声道顺序,默认填 1
if (aacEncoder_SetParam(m_AAChandle, AACENC_CHANNELORDER, 1) != AACENC_OK)
{
return -1;
}
//bits/s
//设置码率
if (aacEncoder_SetParam(m_AAChandle, AACENC_BITRATE, m_iAudioBitrate) != AACENC_OK)
{
return -1;
}
if (23 == m_iEncodMode)
{
//设置封装格式为LATM
if (aacEncoder_SetParam(m_AAChandle, AACENC_TRANSMUX, TT_MP4_LATM_MCP1) != AACENC_OK)
{
return -1;
}
}
else
{
return -1;
}
if (aacEncoder_SetParam(m_AAChandle, AACENC_AFTERBURNER, 0) != AACENC_OK)
{
return -1;
}
//设置编码时采样点的个数
if (aacEncoder_SetParam(m_AAChandle, AACENC_GRANULE_LENGTH, AAC_MAX_SAMPLE_CNT) != AACENC_OK)
{
return -1;
}
//设置复用个数为2
if (aacEncoder_SetParam(m_AAChandle, AACENC_TPSUBFRAMES, 2) != AACENC_OK)
{
return -1;
}
if (aacEncEncode(m_AAChandle, NULL, NULL, NULL, NULL) != AACENC_OK)
{
return -1;
}
//编码的参数信息
AACENC_InfoStruct EncoderInfo;
if (aacEncInfo(m_AAChandle, &EncoderInfo) != AACENC_OK)
{
return -1;
}
//编码后一帧的最大字节数
m_iEncoderBufferSize = EncoderInfo.maxOutBufBytes;
return 0;
}
void CAACEncoder::Destroy()
{
aacEncClose(&m_AAChandle);
}
解码示例用于对AAC-LD,封装格式为LATM复用码流的解码
头文件
#ifndef AAC_DECODE_H
#define AAC_DECODE_H
#include "libAACdec/include/aacdecoder_lib.h"
class CAACDecoder
{
private:
public:
CAACDecoder();
~CAACDecoder();
int Init();
int SetCodecParameters(int Mode, int frameSize);
int DecodeFrame(unsigned char* pEncodedFrame, unsigned int encodedFrameLen);
int GetDecodedDataLen(unsigned char*& pExpandedFrame, int& sample);
private:
int InternalDecodeFrame(unsigned char* pEncodedFrame, unsigned int encodedFrameLen);
void Destroy();
private:
int m_frameSize;
unsigned char* m_pDecodedData;
int m_iDecodeFrameSize;
short* m_pOut;
HANDLE_AACDECODER m_DecoderHandle;
//2->AAC-LC 5->HE-AAC 29->HE-AAC-v2 23->AAC-LD 39->AAC-ELD
int m_iEncodMode;
int m_AudioSample;
#ifdef DECODE_RECORD_FILE
FILE *m_PCMFile;
FILE *m_FromEncoder;
#endif
};
#endif
cpp文件
#include "AACDecoder.h"
#define MB_AAC_IN_BUFF 96000
#define AAC_MONO_SILENCE_FRAME_SIZE 10
#define AAC_STEREO_SILENCE_FRAME_SIZE 11
CAACDecoder::CAACDecoder() :
m_frameSize(0)
, m_AudioSample(0)
, m_pDecodedData(NULL)
, m_iDecodeFrameSize(0)
, m_pOut(NULL)
#ifdef DECODE_RECORD_FILE
, m_FromEncoder(NULL)
, m_PCMFile(NULL)
#endif
{
}
CAACDecoder::~CAACDecoder()
{
Destroy();
}
int CAACDecoder::SetCodecParameters(int Mode, int frameSize)
{
if (23 != Mode)
{//AAC-LD 23
return -1;
}
m_iEncodMode = Mode;
m_frameSize = frameSize;
return 0;
}
int CAACDecoder::GetDecodedDataLen(unsigned char*& pExpandedFrame, int& sample)
{
pExpandedFrame = m_pDecodedData;
sample = m_AudioSample;
int tmp = m_iDecodeFrameSize;
m_iDecodeFrameSize = 0;
return tmp;
}
int CAACDecoder::DecodeFrame(unsigned char* pEncodedFrame, unsigned int encodedFrameLen)
{
#ifdef DECODE_RECORD_FILE
fwrite(pEncodedFrame, encodedFrameLen, 1, m_FromEncoder);
#endif
unsigned int tmp = encodedFrameLen;
unsigned char* pData = pEncodedFrame;
while (encodedFrameLen > 0)
{//对复用的情况,一个RTP会携带多个audio frame,所以这里是个循环
int iLen = InternalDecodeFrame(pData, encodedFrameLen);
if (iLen < 0)
{
return -1;
}
pData += iLen;
encodedFrameLen -= iLen;
}
return 0;
}
int CAACDecoder::Init()
{
//LATM的封装格式
m_DecoderHandle = aacDecoder_Open(TT_MP4_LATM_MCP1, 1);
if (!m_DecoderHandle)
{
return -1;
}
if (aacDecoder_SetParam(m_DecoderHandle, AAC_CONCEAL_METHOD, 0) != AAC_DEC_OK)
{
return -1;
}
#ifdef DECODE_RECORD_FILE
m_PCMFile = fopen("./audiodata/aacdecoder_pcm", "wb");
m_FromEncoder = fopen("./audiodata/aacfromencoder", "wb");
#endif
m_pDecodedData = new unsigned char[MB_AAC_IN_BUFF];
m_pOut = new short[MB_AAC_IN_BUFF];
m_iDecodeFrameSize = 0;
return 0;
}
int CAACDecoder::InternalDecodeFrame(unsigned char* pEncodedFrame, unsigned int encodedFrameLen)
{
unsigned int uBufferSize = MB_AAC_IN_BUFF;
unsigned int valid = encodedFrameLen;
unsigned int iEncodedFrameLen = encodedFrameLen;
AAC_DECODER_ERROR err;
err = aacDecoder_Fill(m_DecoderHandle, &pEncodedFrame, &iEncodedFrameLen, &valid);
if (err != AAC_DEC_OK)
{
return -1;
}
err = aacDecoder_DecodeFrame(m_DecoderHandle, m_pOut, uBufferSize/*/ sizeof(INT_PCM)*/, 0);
if (err != AAC_DEC_OK)
{
return -1;
}
//获取解码后码流的信息
CStreamInfo* info = aacDecoder_GetStreamInfo(m_DecoderHandle);
if (!info)
{
return -1;
}
if (info->frameSize > 0)
{//frameSize为解码后的长度,为固定的几类值,与编码端的设置相关
unsigned char* pDecodedData = m_pDecodedData + m_iDecodeFrameSize;
//采样率
m_AudioSample = info->sampleRate;
//声道*音频帧大小为整个帧的大小
int outputlen = info->numChannels*info->frameSize;
//将16位(INT_PCM为16位)转换为8位
for (int i = 0; i < outputlen; i++)
{
unsigned char* out = &pDecodedData[sizeof(INT_PCM)*i];
unsigned j;
for (j = 0; j < sizeof(INT_PCM); j++)
out[j] = (unsigned char)(m_pOut[i] >> (8 * j));
}
//16位转换为8位是长度大小需要乘以2
m_iDecodeFrameSize += info->numChannels*info->frameSize * 2;
#ifdef DECODE_RECORD_FILE
fwrite(pDecodedData, info->numChannels*info->frameSize * 2, 1, m_PCMFile);
#endif
}
return encodedFrameLen - valid;
}
void CAACDecoder::Destroy()
{
if (m_pDecodedData)
{
delete[]m_pDecodedData;
m_pDecodedData = NULL;
}
if (m_pOut)
{
delete[] m_pOut;
m_pOut = NULL;
}
aacDecoder_Close(m_DecoderHandle);
#ifdef DECODE_RECORD_FILE
fclose(m_PCMFile);
m_PCMFile = NULL;
fclose(m_FromEncoder);
m_FromEncoder = NULL;
#endif
return;
}