libfdk-aac编解码代码示例

背景

前面几篇文章介绍了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 <mutex>

#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;
}




  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mo4776

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值