音频编解码之AAC

音视频应用开发系列文章目录

本文基于fdk-aac封装AAC编码器类AvAac。aac编解码库有faac和fdk-aac,经百度,fdk-aac比较强大,所以基于fdk-aac,首先需要编译fdk-aac,Linux下easy,Windows下可以参考《windows下CMake fdk-aac》。

编码流程

打开编码器 // 初始化一些AAC编码器的参数

编码 

关闭编码器

编码器参数

typedef struct AvAacEncConfig_T{

	AvAacEncFmt format = AvAacEncFmt_AACLC;
	AvAacEncTransType trans_type = AvAacEncTransType_ADTS;
	short bits_per_sample = 16;		// bit
	int sample_rate = 48000;		// Hz
	int bit_rate = 128000;			// bit/second
	short in_channels = 1;
	short band_width = 10000;		// Hz
}AvAacEncConfig;

format:编码的AAC类型,AAC有很多种profile,自行百度。

trans_type:一般使用ADTS

bits_per_sample:每个音频采样点的采样精度

bit_rate:比特率

in_channels:音频通道数

band_width:带宽

打开编码器

int open_encoder(AvAacEncConfig aac_config, int &pcm_frame_len);

aac_config:编码器参数

pcm_frame_len:输出参数,得到一次送入解码器的PCM数据大小。这个参数很重要,只有在初始化编码器后才能得到,为啥说这个参数很重要呢,因为在解码的时候要用到。没有这个参数便不知道一次送入多少RAW PCM数据到编码器编码,送多了,送少了都不行。一个通道的每一帧AAC最大编码输出为768字节

编码

int encode(unsigned char *aac, unsigned char *pcm);

aac:输出编码后的aac数据

pcm:输入的pcm数据,其大小需为pcm_frame_len

关闭编码器

void close_encoder();

AvAac编码器类

AvAac.h

#ifndef _AV_AAC_H_
#define _AV_AAC_H_

/***********************************************************
**	Author:kaychan
**	Data:2019-11-21
**	Mail:[email protected]
**	Explain:a aac codec class base on fdk-aac
***********************************************************/

#include "aacenc_lib.h"

typedef enum AvAacEncFmt_E {

	AvAacEncFmt_AACLC		= 0, // AAC LC 
	AvAacEncFmt_EAAC		= 1, // eAAC(HEAAC or AAC+  or aacPlusV1) 
	AvAacEncFmt_EAACPLUS	= 2, // eAAC+(AAC++ or aacPlusV2) 
	AvAacEncFmt_AACLD		= 3, // AAC LD(Low Delay) 
	AvAacEncFmt_AACELD		= 4, // AAC ELD(Low Delay) 
}AvAacEncFmt;

typedef enum AvAacEncTransType_E {

	AvAacEncTransType_ADTS		= 0,
	AvAacEncTransType_LOAS		= 1,
	AvAacEncTransType_LATM_MCP1 = 2,
}AvAacEncTransType;

typedef struct AvAacEncConfig_T{

	AvAacEncFmt format = AvAacEncFmt_AACLC;
	AvAacEncTransType trans_type = AvAacEncTransType_ADTS;
	short bits_per_sample = 16;		// bit
	int sample_rate = 48000;		// Hz
	int bit_rate = 128000;			// bit/second
	short in_channels = 1;
	short band_width = 10000;		// Hz
}AvAacEncConfig;

class AvAac {

public:
	AvAac();
	~AvAac();
	int open_encoder(AvAacEncConfig aac_config, int &pcm_frame_len);
	int encode(unsigned char *aac, unsigned char *pcm);
	int encode_file(const char *aac_file, const char *pcm_file);
	void close_encoder();
	const char *fdkaac_error2string(AACENC_ERROR e);

private:
	HANDLE_AACENCODER h_aac_encoder_;
	AvAacEncConfig aac_enc_config_;
	int pcm_frame_len_;
};

#endif

AvAac.cpp

#include "AvAac.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define AAC_ENC_MAX_OUTPUT_SIZE		(768 * 8)	// @8ch

AvAac::AvAac() {

	h_aac_encoder_ = NULL;
	pcm_frame_len_ = 0;
}

AvAac::~AvAac() {


}

int AvAac::open_encoder(AvAacEncConfig aac_config, int &pcm_frame_len) {

	aac_enc_config_ = aac_config;

	AACENC_ERROR e;
	e = aacEncOpen((HANDLE_AACENCODER *)&h_aac_encoder_, 0, aac_config.in_channels);
	if (e != AACENC_OK) {

		return e;
	}
	// MPEG AOT
	int aot;
	switch (aac_config.format) {

		default:
		case AvAacEncFmt_AACLC:		aot = AOT_AAC_LC;		break;
		case AvAacEncFmt_EAAC:		aot = AOT_SBR;			break;
		case AvAacEncFmt_EAACPLUS:	aot = AOT_PS;			break;
		case AvAacEncFmt_AACLD:		aot = AOT_ER_AAC_LD;	break;
		case AvAacEncFmt_AACELD:	aot = AOT_ER_AAC_ELD;	break;
	}
	e = aacEncoder_SetParam(h_aac_encoder_, AACENC_AOT, aot);
	if (e != AACENC_OK) {

		return e;
	}
	int eld_sbr = 0;
	if (aot == AOT_ER_AAC_ELD && eld_sbr) {

		e = aacEncoder_SetParam(h_aac_encoder_, AACENC_SBR_MODE, 1);
		if (e != AACENC_OK) {

			return e;
		}
	}
	e = aacEncoder_SetParam(h_aac_encoder_, AACENC_SAMPLERATE, aac_config.sample_rate);
	if (e != AACENC_OK) {

		return e;
	}
	// MPEG channel
	int mode;
	switch (aac_config.in_channels) {

		case 1: mode = MODE_1;       break;
		case 2: mode = MODE_2;       break;
		case 3: mode = MODE_1_2;     break;
		case 4: mode = MODE_1_2_1;   break;
		case 5: mode = MODE_1_2_2;   break;
		case 6: mode = MODE_1_2_2_1; break;
		default: return -1;
	}
	e = aacEncoder_SetParam(h_aac_encoder_, AACENC_CHANNELMODE, mode);
	if (e != AACENC_OK) {

		return e;
	}
	int vbr = 0;
	if (vbr) {

		e = aacEncoder_SetParam(h_aac_encoder_, AACENC_BITRATEMODE, vbr);
		if (e != AACENC_OK) {

			return e;
		}
	}
	else {

		e = aacEncoder_SetParam(h_aac_encoder_, AACENC_BITRATEMODE, 0);
		if (e != AACENC_OK) {

			return e;
		}
		e = aacEncoder_SetParam(h_aac_encoder_, AACENC_BITRATE, aac_config.bit_rate);
		if (e != AACENC_OK) {

			return e;
		}
	}
	// trans type
	TRANSPORT_TYPE tt;
	switch (aac_config.trans_type) {

		default:
		case AvAacEncTransType_ADTS: tt = TT_MP4_ADTS; break;
		case AvAacEncTransType_LOAS: tt = TT_MP4_LOAS; break;
		case AvAacEncTransType_LATM_MCP1: tt = TT_MP4_LATM_MCP1; break;
	}
	e = aacEncoder_SetParam(h_aac_encoder_, AACENC_TRANSMUX, tt);
	if (e != AACENC_OK) {

		return e;
	}
	// band width
	if (aac_config.band_width > 0) {

		int min_bw = (aac_config.sample_rate + 255) >> 8;
		int max_bw = 20000;
		if (aac_config.band_width < min_bw) aac_config.band_width = min_bw;
		if (aac_config.band_width > max_bw) aac_config.band_width = max_bw;
		e = aacEncoder_SetParam(h_aac_encoder_, AACENC_BANDWIDTH, aac_config.band_width);
		if (e != AACENC_OK) {

			return e;
		}
	}
	// initialize
	e = aacEncEncode(h_aac_encoder_, NULL, NULL, NULL, NULL);
	if (e != AACENC_OK) {

		return e;
	}
	AACENC_InfoStruct enc_info = { 0 };
	e = aacEncInfo(h_aac_encoder_, &enc_info);
	if (e != AACENC_OK) {

		return e;
	}
	pcm_frame_len_ = enc_info.inputChannels * enc_info.frameLength * 2;
	pcm_frame_len = pcm_frame_len_;
	return AACENC_OK;
}

int AvAac::encode(unsigned char *aac, unsigned char *pcm) {

	AACENC_BufDesc in_buf = { 0 };
	AACENC_BufDesc out_buf = { 0 };
	AACENC_InArgs in_args = { 0 };
	AACENC_OutArgs out_args = { 0 };
	AACENC_ERROR e;

	// config in_bug and out_buf
	unsigned char ancillary_buf[64];
	AACENC_MetaData meta_data_setup;
	void *ibufs[] = { pcm, ancillary_buf, &meta_data_setup };
	int ibuf_ids[] = { IN_AUDIO_DATA, IN_ANCILLRY_DATA, IN_METADATA_SETUP };
	int ibuf_sizes[] = { pcm_frame_len_, sizeof(ancillary_buf), sizeof(meta_data_setup) };
	int ibuf_element_sizes[] = { sizeof(unsigned char), sizeof(unsigned char), sizeof(AACENC_MetaData) };
	in_buf.numBufs = sizeof(ibufs) / sizeof(void *);
	in_buf.bufs = (void **)&ibufs;
	in_buf.bufferIdentifiers = ibuf_ids;
	in_buf.bufSizes = ibuf_sizes;
	in_buf.bufElSizes = ibuf_element_sizes;

	void *obufs[] = { aac };
	int obuf_ids[] = { OUT_BITSTREAM_DATA };
	int obuf_sizes[] = { AAC_ENC_MAX_OUTPUT_SIZE };
	int obuf_element_sizes[] = { sizeof(unsigned char) };
	out_buf.numBufs = sizeof(obufs) / sizeof(void *);
	out_buf.bufs = (void **)&aac;
	out_buf.bufferIdentifiers = obuf_ids;
	out_buf.bufSizes = obuf_sizes;
	out_buf.bufElSizes = obuf_element_sizes;

	in_args.numAncBytes = 0;
	in_args.numInSamples = AAC_ENC_MAX_OUTPUT_SIZE;

	// start encode
	e = aacEncEncode(h_aac_encoder_, &in_buf, &out_buf, &in_args, &out_args);
	if (e != AACENC_OK) {

		if (e == AACENC_ENCODE_EOF) {

			return 0; // eof
		}
		return -1;
	}
	return out_args.numOutBytes;
}

int AvAac::encode_file(const char *aac_file, const char *pcm_file) {

	FILE *ifile = fopen(pcm_file, "rb");
	FILE *ofile = fopen(aac_file, "wb");
	if (ifile && ofile) {

		int r = -1;
		do {

			unsigned char *ibuf = (unsigned char *)malloc(pcm_frame_len_);
			memset(ibuf, 0, pcm_frame_len_);
			r = fread(ibuf, 1, pcm_frame_len_, ifile);
			if (r > 0) {

				unsigned char obuf[AAC_ENC_MAX_OUTPUT_SIZE];
				memset(obuf, 0, sizeof(obuf));
				int olen = encode(obuf, ibuf);
				fwrite(obuf, 1, olen, ofile);
			}
			free(ibuf);
		} while (r > 0);
		fclose(ifile);
		fclose(ofile);
		return 0;
	}
	return -1;
}

void AvAac::close_encoder() {

	aacEncClose(&h_aac_encoder_);
}

const char *AvAac::fdkaac_error2string(AACENC_ERROR e) {

	switch (e) {

		case AACENC_OK: return "No error";
		case AACENC_INVALID_HANDLE: return "Invalid handle";
		case AACENC_MEMORY_ERROR: return "Memory allocation error";
		case AACENC_UNSUPPORTED_PARAMETER: return "Unsupported parameter";
		case AACENC_INVALID_CONFIG: return "Invalid config";
		case AACENC_INIT_ERROR: return "Initialization error";
		case AACENC_INIT_AAC_ERROR: return "AAC library initialization error";
		case AACENC_INIT_SBR_ERROR: return "SBR library initialization error";
		case AACENC_INIT_TP_ERROR: return "Transport library initialization error";
		case AACENC_INIT_META_ERROR: return "Metadata library initialization error";
		case AACENC_ENCODE_ERROR: return "Encoding error";
		case AACENC_ENCODE_EOF: return "End of file";
		default: return "Unknown error";
	}
}

调用实例

AvAac aac;
int pcm_len;
AvAacEncConfig aac_config;
aac_config.format = AvAacEncFmt_AACLC;
aac_config.bit_rate = 64000;
aac.open_encoder(aac_config, pcm_len);
unsigned char *ibuf = (unsigned char *)malloc(pcm_len);
// set pcm data to ibuf here···
unsigned char obuf[AAC_ENC_MAX_OUTPUT_SIZE];
int olen = aac.encode(obuf, ibuf);
// do obuf what you want···
发布了131 篇原创文章 · 获赞 195 · 访问量 38万+

猜你喜欢

转载自blog.csdn.net/KayChanGEEK/article/details/103355961