使用FAAD库对AAC格式的音频进行解码

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

 

 

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值