音频编解码之AAC
《音视频应用开发系列文章目录》本文基于fdk-aac封装AAC编码器类AvAac。aac编解码库有faac和fdk-aac,经百度,fdk-aac比较强大,所以基于fdk-aac,首先需要编译fdk-aac,Linux下easy,Windows下可以参考《windows下CMake fdk-aac》。编码流程打开编码器 // 初始化一些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:1203375695@qq.com
** 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···
更多推荐
已为社区贡献3条内容
所有评论(0)