1、AAC音频文件格式
(1) AAC的音频文件格式有ADIF & ADTS:
我主要做的是ADTS,我们就分析ADTS格式,下面的图可以反映问题。
可以参考:https://www.jianshu.com/p/b5ca697535bd
但是这里的ADTS Frame帧中AAC ES的大小不是固定的,这就造成每一帧ADTS数据大小都不同,可以是几百字节到一千多个字节。ADTS帧大小不同,FAAD库就为它设计了一个特别的解码函数,我们待会分析。
2、解码函数分析
unsigned long NEAACAPI NeAACDecGetCapabilities(void);
//这个函数是返回该函数库可以支持的文件格式
#define LC_DEC_CAP (1<<0) /* Can decode LC */
#define MAIN_DEC_CAP (1<<1) /* Can decode MAIN */
#define LTP_DEC_CAP (1<<2) /* Can decode LTP */
#define LD_DEC_CAP (1<<3) /* Can decode LD */
#define ERROR_RESILIENCE_CAP (1<<4) /* Can decode ER */
#define FIXED_POINT_CAP (1<<5) /* Fixed point */
NeAACDecHandle NEAACAPI NeAACDecOpen(void);
//解码open函数,返回一个“解码器的头”,简单类比为open()函数返回的文件描述符fd
void NEAACAPI NeAACDecClose(NeAACDecHandle hDecoder);
//同样类比close()函数,输入的参数就是解码open函数,打开的“解码器头”
NeAACDecConfigurationPtr NEAACAPI NeAACDecGetCurrentConfiguration(NeAACDecHandle hDecoder);
//得到解码器的配置信息
unsigned char NEAACAPI NeAACDecSetConfiguration(NeAACDecHandle hDecoder, NeAACDecConfigurationPtr config);
//设置解码器信息,传入的就是配置信息
long NEAACAPI NeAACDecInit(NeAACDecHandle hDecoder, unsigned char *buffer, unsigned long buffer_size, unsigned long *samplerate, unsigned char *channels);
//值得一说的是初始化函数,第一个“解码器的头”,
//重点:第二个“要解码的buffer”,这个buffer只要传一部分进行,初始化函数就会识别文件格式是ADTS还是ADIF
//第三个参数:buffer的大小
//第四采样率,第五通道数
void* NEAACAPI NeAACDecDecode(NeAACDecHandle hDecoder, NeAACDecFrameInfo *hInfo, unsigned char *buffer, unsigned long buffer_size);
//重点:是解码函数传进行的hInfo,这个作为输出型参数;
typedef struct NeAACDecFrameInfo
{
unsigned long bytesconsumed;
unsigned long samples;
unsigned char channels;
unsigned char error;
unsigned long samplerate;
unsigned char sbr;
unsigned char object_type;
unsigned char header_type;
unsigned char num_front_channels;
unsigned char num_side_channels;
unsigned char num_back_channels;
unsigned char num_lfe_channels;
unsigned char channel_position[64];
unsigned char ps;
} NeAACDecFrameInfo;
//最重要的:第一个参数,本次解码消耗的字节数
//第三个参数,为0则表示无错误
3、解码示范代码
#include <stdio.h>
#include <neaacdec.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define MAX_CHANNELS 6
#define MAX_PERCENTS 384
#define faad_fopen(X,Y) fopen((X),(Y))
#define min(a,b) ( (a) < (b) ? (a) : (b) )
static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0};
typedef struct
{
int toStdio;
int outputFormat;
FILE *sndfile;
unsigned int fileType;
unsigned long samplerate;
unsigned int bits_per_sample;
unsigned int channels;
unsigned long total_samples;
long channelMask;
} audio_file;
typedef struct {
long bytes_into_buffer;
long bytes_consumed;
long file_offset;
unsigned char *buffer;
int at_eof;
FILE *infile;
} aac_buffer;
audio_file *open_audio_file(char *infile, int samplerate, int channels,
int outputFormat, int fileType, long channelMask)
{
audio_file *aufile = malloc(sizeof(audio_file));
aufile->outputFormat = outputFormat;
aufile->samplerate = samplerate;
aufile->channels = channels;
aufile->total_samples = 0;
aufile->fileType = fileType;
aufile->channelMask = channelMask;
switch (outputFormat)
{
case FAAD_FMT_16BIT:
aufile->bits_per_sample = 16;
break;
default:
if (aufile) free(aufile);
return NULL;
}
aufile->toStdio = 0;
aufile->sndfile = faad_fopen(infile, "wb");
if (aufile->sndfile == NULL)
{
if (aufile) free(aufile);
return NULL;
}
return aufile;
}
static int write_audio_16bit(audio_file *aufile, void *sample_buffer,
unsigned int samples)
{
int ret;
unsigned int i;
short *sample_buffer16 = (short*)sample_buffer;
char *data = malloc(samples*aufile->bits_per_sample*sizeof(char)/8);
aufile->total_samples += samples;
if (aufile->channels == 6 && aufile->channelMask)
{
for (i = 0; i < samples; i += aufile->channels)
{
short r1, r2, r3, r4, r5, r6;
r1 = sample_buffer16[i];
r2 = sample_buffer16[i+1];
r3 = sample_buffer16[i+2];
r4 = sample_buffer16[i+3];
r5 = sample_buffer16[i+4];
r6 = sample_buffer16[i+5];
sample_buffer16[i] = r2;
sample_buffer16[i+1] = r3;
sample_buffer16[i+2] = r1;
sample_buffer16[i+3] = r6;
sample_buffer16[i+4] = r4;
sample_buffer16[i+5] = r5;
}
}
for (i = 0; i < samples; i++)
{
data[i*2] = (char)(sample_buffer16[i] & 0xFF);
data[i*2+1] = (char)((sample_buffer16[i] >> 8) & 0xFF);
}
ret = fwrite(data, samples, aufile->bits_per_sample/8, aufile->sndfile);
if (data) free(data);
return ret;
}
int write_audio_file(audio_file *aufile, void *sample_buffer, int samples, int offset)
{
char *buf = (char *)sample_buffer;
switch (aufile->outputFormat)
{
case FAAD_FMT_16BIT:
return write_audio_16bit(aufile, buf + offset*2, samples);
default:
return 0;
}
return 0;
}
void close_audio_file(audio_file *aufile)
{
if (aufile->toStdio == 0)
fclose(aufile->sndfile);
if (aufile) free(aufile);
}
static int decodeAACfile(char *aacfile, char *sndfile)
{
unsigned long samplerate;
unsigned char channels;
void *sample_buffer;
audio_file *aufile = NULL;
NeAACDecHandle hDecoder;
NeAACDecFrameInfo frameInfo;
NeAACDecConfigurationPtr config;
int bread, fileread;
aac_buffer b;
memset(&b, 0, sizeof(aac_buffer));
b.infile = faad_fopen(aacfile, "rb");
if (b.infile == NULL)
{
/* unable to open file */
printf("Error opening file: %s\n", aacfile);
return 1;
}
fseek(b.infile, 0, SEEK_END);
fileread = ftell(b.infile);
fseek(b.infile, 0, SEEK_SET);
if (!(b.buffer = (unsigned char*)malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS)))
{
printf("Memory allocation error\n");
return 0;
}
memset(b.buffer, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS);
bread = fread(b.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, b.infile);
printf("bread = %d\n",bread);
b.bytes_into_buffer = bread;
b.bytes_consumed = 0;
b.file_offset = 0;
if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
b.at_eof = 1;
hDecoder = NeAACDecOpen();
/* Set the default object type and samplerate */
/* This is useful for RAW AAC files */
config = NeAACDecGetCurrentConfiguration(hDecoder);
config->defSampleRate = 44100;
config->defObjectType = LC;
config->outputFormat = FAAD_FMT_16BIT;
config->downMatrix = 0;
config->useOldADTSFormat = 0;
NeAACDecSetConfiguration(hDecoder, config);
fseek(b.infile, 0, SEEK_SET);
bread = fread(b.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, b.infile);
printf("FAAD_MIN_STREAMSIZE = %d,MAX_CHANNELS = %d\n",FAAD_MIN_STREAMSIZE,MAX_CHANNELS);
if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
b.at_eof = 1;
else
b.at_eof = 0;
b.bytes_into_buffer = bread;
b.bytes_consumed = 0;
b.file_offset = 0;
if ((bread = NeAACDecInit(hDecoder, b.buffer,b.bytes_into_buffer, &samplerate, &channels)) < 0)
{
/* If some error initializing occured, skip the file */
printf("Error initializing decoder library.\n");
if (b.buffer)
free(b.buffer);
NeAACDecClose(hDecoder);
if (b.infile != stdin)
fclose(b.infile);
return 1;
}
aufile = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels,FAAD_FMT_16BIT, 2, 0);
printf("bread = %d\n",bread);
do
{
if (b.bytes_consumed > 0)
{
if (b.bytes_into_buffer)
{
// printf("b.bytes_into_buffer = %d\n",b.bytes_into_buffer);
// printf("b.bytes_consumed = %d\n",b.bytes_consumed);
memmove((void*)b.buffer, (void*)(b.buffer + b.bytes_consumed),
b.bytes_into_buffer*sizeof(unsigned char));
}
if (!b.at_eof)
{
bread = fread((void*)(b.buffer + b.bytes_into_buffer), 1,
b.bytes_consumed, b.infile);
if (bread != b.bytes_consumed)
b.at_eof = 1;
b.bytes_into_buffer += bread;
}
b.bytes_consumed = 0;
}
sample_buffer = NeAACDecDecode(hDecoder, &frameInfo,
b.buffer, b.bytes_into_buffer);
printf("frameInfo.bytesconsumed = %lu\n",frameInfo.bytesconsumed);
/* update buffer indices */
//printf("frameInfo.bytesconsumed = %d\n",frameInfo.bytesconsumed);
int bytes = (int)frameInfo.bytesconsumed;
if((b.bytes_into_buffer > 0) && (bytes > 0))
{
int chunk = min(bytes, b.bytes_into_buffer);
bytes -= chunk;
b.file_offset += chunk;
b.bytes_consumed = chunk;
// printf("b.bytes_into_buffer = %d\n",b.bytes_into_buffer);
b.bytes_into_buffer -= chunk;
// printf("b.bytes_into_buffer = %d\n",b.bytes_into_buffer);
}
if (frameInfo.error > 0)
{
printf("Error: %s\n",
NeAACDecGetErrorMessage(frameInfo.error));
}
if ((frameInfo.error == 0) && (frameInfo.samples > 0))
{
if (write_audio_file(aufile, sample_buffer, frameInfo.samples, 0) == 0)
break;
}
int bread;
if (b.bytes_into_buffer == 0)
sample_buffer = NULL; /* to make sure it stops now */
} while (sample_buffer != NULL);
NeAACDecClose(hDecoder);
close_audio_file(aufile);
if (b.buffer)
free(b.buffer);
return frameInfo.error;
}
int main(int argc,char* argv[])
{
printf("hello word\n");
char* aacFileName = "44100_16_2.aac";
char* audioFileName = "test.pcm";
char* adtsFileName = NULL;
int writeToStdio = 0;
int def_srate = 44100;
int object_type = 2;//LC
int outputFormat = 1;//FAAD_FMT_16BIT
int format = 2;
decodeAACfile(aacFileName, audioFileName);
return 0;
}
4、 44100_16_2.aac音频文档包括开源FAAD库都在这里
https://github.com/knik0/faad2.git