將faad2轉碼方法移植到C++

faad2中的測試工程在文件夾frontend中,主要代碼在main.c和audio.c文件中。

這裏只實現AAC轉碼WAV的功能。

注:編譯環境爲VS2012,faad2-2.7。

1、main.c

分析main.c文件中的代碼,將靜態方法和常量分別摘取出來,放入CFaad2Helper類和Constants類。

Faad2Helper.h

#pragma once

#include "neaacdec.h"
#include "mp4ff.h"

#include <string>
using namespace std;

/* FAAD file buffering routines */
typedef struct {
	long bytes_into_buffer;
	long bytes_consumed;
	long file_offset;
	unsigned char *buffer;
	int at_eof;
	FILE *infile;
} aac_buffer;

//Faad2靜態方法幫助類
class CFaad2Helper
{
public:
	CFaad2Helper(void);
	~CFaad2Helper(void);

	static int decodeAACfile(char *aacfile, char *sndfile, char *adts_fn, int to_stdout,
		int def_srate, int object_type, int outputFormat, int fileType,
		int downMatrix, int infoOnly, int adts_out, int old_format,
		float *song_length);

	static int decodeMP4file(char *mp4file, char *sndfile, char *adts_fn, int to_stdout,
		int outputFormat, int fileType, int downMatrix, int noGapless,
		int infoOnly, int adts_out, float *song_length);

	static string GetLastErrMsg();

private:
	static void faad_fprintf(const char *prefix, const char *msg);
	static void faad_fprintf(const char *msg);

	static void print_channel_info(NeAACDecFrameInfo *frameInfo);

	static int fill_buffer(aac_buffer *b);
	static void advance_buffer(aac_buffer *b, int bytes);
	static int adts_parse(aac_buffer *b, int *bitrate, float *length);
	static long aacChannelConfig2wavexChannelMask(NeAACDecFrameInfo *hInfo);
	static char *position2string(int position);
	static int FindAdtsSRIndex(int sr);
	static unsigned char *MakeAdtsHeader(int *dataSize, NeAACDecFrameInfo *hInfo, int old_format);
	static int GetAACTrack(mp4ff_t *infile);

private:
	static string m_sLastErrMsg;	//錯誤信息
};

Faad2Helper.cpp

#include "stdafx.h"
#include "Faad2Helper.h"
#include "Audio.h"
#include "Constants.h"

#include <cstdio>
#include <sstream>

static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0};

string CFaad2Helper::m_sLastErrMsg = "";

CFaad2Helper::CFaad2Helper(void)
{
}


CFaad2Helper::~CFaad2Helper(void)
{
}

string CFaad2Helper::GetLastErrMsg()
{
	return m_sLastErrMsg;
}

void CFaad2Helper::faad_fprintf(const char *prefix, const char *msg)
{
	std::stringstream ss;
	ss.clear();
	ss.str("");
	ss << "打開文件錯誤:" << msg;

	m_sLastErrMsg = ss.str();
}
void CFaad2Helper::faad_fprintf(const char *msg)
{
	m_sLastErrMsg = msg;
}

void CFaad2Helper::print_channel_info(NeAACDecFrameInfo *frameInfo)
{
	/* print some channel info */
	//將此函數置爲空
#ifdef PRINT_CHANNEL_INFO
	int i;
	long channelMask = aacChannelConfig2wavexChannelMask(frameInfo);

	faad_fprintf(stderr, "  ---------------------\n");
	if (frameInfo->num_lfe_channels > 0)
	{
		faad_fprintf(stderr, " | Config: %2d.%d Ch     |", frameInfo->channels-frameInfo->num_lfe_channels, frameInfo->num_lfe_channels);
	} else {
		faad_fprintf(stderr, " | Config: %2d Ch       |", frameInfo->channels);
	}
	if (channelMask)
		faad_fprintf(stderr, " WARNING: channels are reordered according to\n");
	else
		faad_fprintf(stderr, "\n");
	faad_fprintf(stderr, "  ---------------------");
	if (channelMask)
		faad_fprintf(stderr, "  MS defaults defined in WAVE_FORMAT_EXTENSIBLE\n");
	else
		faad_fprintf(stderr, "\n");
	faad_fprintf(stderr, " | Ch |    Position    |\n");
	faad_fprintf(stderr, "  ---------------------\n");
	for (i = 0; i < frameInfo->channels; i++)
	{
		faad_fprintf(stderr, " | %.2d | %-14s |\n", i, position2string((int)frameInfo->channel_position[i]));
	}
	faad_fprintf(stderr, "  ---------------------\n");
	faad_fprintf(stderr, "\n");
#endif // PRINT_CHANNEL_INFO
}

int CFaad2Helper::fill_buffer(aac_buffer *b)
{
	int bread;

	if (b->bytes_consumed > 0)
	{
		if (b->bytes_into_buffer)
		{
			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;

		if (b->bytes_into_buffer > 3)
		{
			if (memcmp(b->buffer, "TAG", 3) == 0)
				b->bytes_into_buffer = 0;
		}
		if (b->bytes_into_buffer > 11)
		{
			if (memcmp(b->buffer, "LYRICSBEGIN", 11) == 0)
				b->bytes_into_buffer = 0;
		}
		if (b->bytes_into_buffer > 8)
		{
			if (memcmp(b->buffer, "APETAGEX", 8) == 0)
				b->bytes_into_buffer = 0;
		}
	}

	return 1;
}

void CFaad2Helper::advance_buffer(aac_buffer *b, int bytes)
{
	b->file_offset += bytes;
	b->bytes_consumed = bytes;
	b->bytes_into_buffer -= bytes;
	if (b->bytes_into_buffer < 0)
		b->bytes_into_buffer = 0;
}

int CFaad2Helper::adts_parse(aac_buffer *b, int *bitrate, float *length)
{
	int frames, frame_length;
	int t_framelength = 0;
	int samplerate;
	float frames_per_sec, bytes_per_frame;

	/* Read all frames to ensure correct time and bitrate */
	for (frames = 0; /* */; frames++)
	{
		fill_buffer(b);

		if (b->bytes_into_buffer > 7)
		{
			/* check syncword */
			if (!((b->buffer[0] == 0xFF)&&((b->buffer[1] & 0xF6) == 0xF0)))
				break;

			if (frames == 0)
				samplerate = adts_sample_rates[(b->buffer[2]&0x3c)>>2];

			frame_length = ((((unsigned int)b->buffer[3] & 0x3)) << 11)
				| (((unsigned int)b->buffer[4]) << 3) | (b->buffer[5] >> 5);

			t_framelength += frame_length;

			if (frame_length > b->bytes_into_buffer)
				break;

			advance_buffer(b, frame_length);
		} else {
			break;
		}
	}

	frames_per_sec = (float)samplerate/1024.0f;
	if (frames != 0)
		bytes_per_frame = (float)t_framelength/(float)(frames*1000);
	else
		bytes_per_frame = 0;
	*bitrate = (int)(8. * bytes_per_frame * frames_per_sec + 0.5);
	if (frames_per_sec != 0)
		*length = (float)frames/frames_per_sec;
	else
		*length = 1;

	return 1;
}

long CFaad2Helper::aacChannelConfig2wavexChannelMask(NeAACDecFrameInfo *hInfo)
{
	if (hInfo->channels == 6 && hInfo->num_lfe_channels)
	{
		return SPEAKER_FRONT_LEFT + SPEAKER_FRONT_RIGHT +
			SPEAKER_FRONT_CENTER + SPEAKER_LOW_FREQUENCY +
			SPEAKER_BACK_LEFT + SPEAKER_BACK_RIGHT;
	} else {
		return 0;
	}
}

char* CFaad2Helper::position2string(int position)
{
	switch (position)
	{
	case FRONT_CHANNEL_CENTER: return "Center front";
	case FRONT_CHANNEL_LEFT:   return "Left front";
	case FRONT_CHANNEL_RIGHT:  return "Right front";
	case SIDE_CHANNEL_LEFT:    return "Left side";
	case SIDE_CHANNEL_RIGHT:   return "Right side";
	case BACK_CHANNEL_LEFT:    return "Left back";
	case BACK_CHANNEL_RIGHT:   return "Right back";
	case BACK_CHANNEL_CENTER:  return "Center back";
	case LFE_CHANNEL:          return "LFE";
	case UNKNOWN_CHANNEL:      return "Unknown";
	default: return "";
	}

	return "";
}

int CFaad2Helper::FindAdtsSRIndex(int sr)
{
	int i;

	for (i = 0; i < 16; i++)
	{
		if (sr == adts_sample_rates[i])
			return i;
	}
	return 16 - 1;
}

unsigned char* CFaad2Helper::MakeAdtsHeader(int *dataSize, NeAACDecFrameInfo *hInfo, int old_format)
{
	unsigned char *data;
	int profile = (hInfo->object_type - 1) & 0x3;
	int sr_index = ((hInfo->sbr == SBR_UPSAMPLED) || (hInfo->sbr == NO_SBR_UPSAMPLED)) ?
		FindAdtsSRIndex(hInfo->samplerate / 2) : FindAdtsSRIndex(hInfo->samplerate);
	int skip = (old_format) ? 8 : 7;
	int framesize = skip + hInfo->bytesconsumed;

	if (hInfo->header_type == ADTS)
		framesize -= skip;

	*dataSize = 7;

	data = (unsigned char *)malloc(*dataSize * sizeof(unsigned char));
	memset(data, 0, *dataSize * sizeof(unsigned char));

	data[0] += 0xFF; /* 8b: syncword */

	data[1] += 0xF0; /* 4b: syncword */
	/* 1b: mpeg id = 0 */
	/* 2b: layer = 0 */
	data[1] += 1; /* 1b: protection absent */

	data[2] += ((profile << 6) & 0xC0); /* 2b: profile */
	data[2] += ((sr_index << 2) & 0x3C); /* 4b: sampling_frequency_index */
	/* 1b: private = 0 */
	data[2] += ((hInfo->channels >> 2) & 0x1); /* 1b: channel_configuration */

	data[3] += ((hInfo->channels << 6) & 0xC0); /* 2b: channel_configuration */
	/* 1b: original */
	/* 1b: home */
	/* 1b: copyright_id */
	/* 1b: copyright_id_start */
	data[3] += ((framesize >> 11) & 0x3); /* 2b: aac_frame_length */

	data[4] += ((framesize >> 3) & 0xFF); /* 8b: aac_frame_length */

	data[5] += ((framesize << 5) & 0xE0); /* 3b: aac_frame_length */
	data[5] += ((0x7FF >> 6) & 0x1F); /* 5b: adts_buffer_fullness */

	data[6] += ((0x7FF << 2) & 0x3F); /* 6b: adts_buffer_fullness */
	/* 2b: num_raw_data_blocks */

	return data;
}

int CFaad2Helper::GetAACTrack(mp4ff_t *infile)
{
	/* find AAC track */
	int i, rc;
	int numTracks = mp4ff_total_tracks(infile);

	for (i = 0; i < numTracks; i++)
	{
		unsigned char *buff = NULL;
		int buff_size = 0;
		mp4AudioSpecificConfig mp4ASC;

		mp4ff_get_decoder_config(infile, i, &buff, (unsigned int*)&buff_size);

		if (buff)
		{
			rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC);
			free(buff);

			if (rc < 0)
				continue;
			return i;
		}
	}

	/* can't decode this */
	return -1;
}

#pragma region MyRegion
int CFaad2Helper::decodeAACfile(char *aacfile, char *sndfile, char *adts_fn, int to_stdout,
						 int def_srate, int object_type, int outputFormat, int fileType,
						 int downMatrix, int infoOnly, int adts_out, int old_format,
						 float *song_length)
{
	int tagsize;
	unsigned long samplerate;
	unsigned char channels;
	void *sample_buffer;

	audio_file *aufile;

	FILE *adtsFile = NULL;
	unsigned char *adtsData;
	int adtsDataSize;

	NeAACDecHandle hDecoder;
	NeAACDecFrameInfo frameInfo;
	NeAACDecConfigurationPtr config;

	char percents[200];
	int percent, old_percent = -1;
	int bread, fileread;
	int header_type = 0;
	int bitrate = 0;
	float length = 0;

	int first_time = 1;

	aac_buffer b;

	memset(&b, 0, sizeof(aac_buffer));

	if (adts_out)
	{
		adtsFile = fopen(adts_fn, "wb");
		//fopen_s(&adtsFile, adts_fn, "wb");
		if (adtsFile == NULL)
		{
			faad_fprintf("打開文件錯誤:", adts_fn);
			//faad_fprintf(stderr, "Error opening file: %s\n", adts_fn);
			return 1;
		}
	}

	b.infile = fopen(aacfile, "rb");
	//fopen_s(&b.infile, aacfile, "wb");
	if (b.infile == NULL)
	{
		/* unable to open file */
		faad_fprintf("打開文件錯誤:", aacfile);
		//faad_fprintf(stderr, "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)))
	{
		faad_fprintf("內存分配錯誤");
		//faad_fprintf(stderr, "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);
	b.bytes_into_buffer = bread;
	b.bytes_consumed = 0;
	b.file_offset = 0;

	if (bread != FAAD_MIN_STREAMSIZE*MAX_CHANNELS)
		b.at_eof = 1;

	tagsize = 0;
	if (!memcmp(b.buffer, "ID3", 3))
	{
		/* high bit is not used */
		tagsize = (b.buffer[6] << 21) | (b.buffer[7] << 14) |
			(b.buffer[8] <<  7) | (b.buffer[9] <<  0);

		tagsize += 10;
		advance_buffer(&b, tagsize);
		fill_buffer(&b);
	}

	hDecoder = NeAACDecOpen();

	/* Set the default object type and samplerate */
	/* This is useful for RAW AAC files */
	config = NeAACDecGetCurrentConfiguration(hDecoder);
	if (def_srate)
		config->defSampleRate = def_srate;
	config->defObjectType = object_type;
	config->outputFormat = outputFormat;
	config->downMatrix = downMatrix;
	config->useOldADTSFormat = old_format;
	//config->dontUpSampleImplicitSBR = 1;	//打開這個參數可以解決解碼後的通道數不正確的問題
	NeAACDecSetConfiguration(hDecoder, config);

	/* get AAC infos for printing */
	header_type = 0;
	if ((b.buffer[0] == 0xFF) && ((b.buffer[1] & 0xF6) == 0xF0))
	{
		adts_parse(&b, &bitrate, &length);
		fseek(b.infile, tagsize, SEEK_SET);

		bread = fread(b.buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, b.infile);
		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 = tagsize;

		header_type = 1;
	}
	else if (memcmp(b.buffer, "ADIF", 4) == 0) {
		int skip_size = (b.buffer[4] & 0x80) ? 9 : 0;
		bitrate = ((unsigned int)(b.buffer[4 + skip_size] & 0x0F)<<19) |
			((unsigned int)b.buffer[5 + skip_size]<<11) |
			((unsigned int)b.buffer[6 + skip_size]<<3) |
			((unsigned int)b.buffer[7 + skip_size] & 0xE0);

		length = (float)fileread;
		if (length != 0)
		{
			length = ((float)length*8.f)/((float)bitrate) + 0.5f;
		}

		bitrate = (int)((float)bitrate/1000.0f + 0.5f);

		header_type = 2;
	}

	*song_length = length;

	fill_buffer(&b);
	if ((bread = NeAACDecInit(hDecoder, b.buffer,
		b.bytes_into_buffer, &samplerate, &channels)) < 0)
	{
		/* If some error initializing occured, skip the file */
		faad_fprintf("初始化解碼庫錯誤");
		//faad_fprintf(stderr, "Error initializing decoder library.\n");
		if (b.buffer)
			free(b.buffer);
		NeAACDecClose(hDecoder);
		fclose(b.infile);
		return 1;
	}
	advance_buffer(&b, bread);
	fill_buffer(&b);

	/* print AAC file info */
	/*
	faad_fprintf(stderr, "%s file info:\n", aacfile);
	switch (header_type)
	{
	case 0:
		faad_fprintf(stderr, "RAW\n\n");
		break;
	case 1:
		faad_fprintf(stderr, "ADTS, %.3f sec, %d kbps, %d Hz\n\n",
			length, bitrate, samplerate);
		break;
	case 2:
		faad_fprintf(stderr, "ADIF, %.3f sec, %d kbps, %d Hz\n\n",
			length, bitrate, samplerate);
		break;
	}*/

	if (infoOnly)
	{
		NeAACDecClose(hDecoder);
		fclose(b.infile);
		if (b.buffer)
			free(b.buffer);
		return 0;
	}

	do
	{
		sample_buffer = NeAACDecDecode(hDecoder, &frameInfo,
			b.buffer, b.bytes_into_buffer);

		if (adts_out == 1)
		{
			int skip = (old_format) ? 8 : 7;
			adtsData = MakeAdtsHeader(&adtsDataSize, &frameInfo, old_format);

			/* write the adts header */
			fwrite(adtsData, 1, adtsDataSize, adtsFile);

			/* write the frame data */
			if (frameInfo.header_type == ADTS)
				fwrite(b.buffer + skip, 1, frameInfo.bytesconsumed - skip, adtsFile);
			else
				fwrite(b.buffer, 1, frameInfo.bytesconsumed, adtsFile);
		}

		/* update buffer indices */
		advance_buffer(&b, frameInfo.bytesconsumed);

		if (frameInfo.error > 0)
		{
			faad_fprintf("解碼錯誤:", NeAACDecGetErrorMessage(frameInfo.error));
// 			faad_fprintf(stderr, "Error: %s\n",
// 				NeAACDecGetErrorMessage(frameInfo.error));
		}

		/* open the sound file now that the number of channels are known */
		if (first_time && !frameInfo.error)
		{
			/* print some channel info */
			print_channel_info(&frameInfo);

			if (!adts_out)
			{
				/* open output file */
				if (!to_stdout)
				{
					aufile = Audio::open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels,
						outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo));
				} else {
					aufile = Audio::open_audio_file("-", frameInfo.samplerate, frameInfo.channels,
						outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo));
				}
				if (aufile == NULL)
				{
					if (b.buffer)
						free(b.buffer);
					NeAACDecClose(hDecoder);
					fclose(b.infile);
					return 0;
				}
			} else {
				faad_fprintf("寫輸出MPEG-4 AAC ADTS文件", aacfile);
				//faad_fprintf(stderr, "Writing output MPEG-4 AAC ADTS file.\n\n");
			}
			first_time = 0;
		}

		percent = min((int)(b.file_offset*100)/fileread, 100);
		if (percent > old_percent)
		{
			old_percent = percent;
			sprintf_s(percents, "%d%% decoding %s.", percent, aacfile);
			//faad_fprintf(stderr, "%s\r", percents);
#ifdef _WIN32
			//SetConsoleTitle(percents);
#endif
		}

		if ((frameInfo.error == 0) && (frameInfo.samples > 0) && (!adts_out))
		{
			if (Audio::write_audio_file(aufile, sample_buffer, frameInfo.samples, 0) == 0)
				break;
		}

		/* fill buffer */
		fill_buffer(&b);

		if (b.bytes_into_buffer == 0)
			sample_buffer = NULL; /* to make sure it stops now */

	} while (sample_buffer != NULL);

	NeAACDecClose(hDecoder);

	if (adts_out == 1)
	{
		fclose(adtsFile);
	}

	fclose(b.infile);

	if (!first_time && !adts_out)
		Audio::close_audio_file(aufile);

	if (b.buffer)
		free(b.buffer);

	return frameInfo.error;
}
#pragma endregion

Constants.h

#pragma once

#define MAX_CHANNELS 6 /* make this higher to support files with
                          more channels */

/* MicroSoft channel definitions */
#define SPEAKER_FRONT_LEFT             0x1
#define SPEAKER_FRONT_RIGHT            0x2
#define SPEAKER_FRONT_CENTER           0x4
#define SPEAKER_LOW_FREQUENCY          0x8
#define SPEAKER_BACK_LEFT              0x10
#define SPEAKER_BACK_RIGHT             0x20
#define SPEAKER_FRONT_LEFT_OF_CENTER   0x40
#define SPEAKER_FRONT_RIGHT_OF_CENTER  0x80
#define SPEAKER_BACK_CENTER            0x100
#define SPEAKER_SIDE_LEFT              0x200
#define SPEAKER_SIDE_RIGHT             0x400
#define SPEAKER_TOP_CENTER             0x800
#define SPEAKER_TOP_FRONT_LEFT         0x1000
#define SPEAKER_TOP_FRONT_CENTER       0x2000
#define SPEAKER_TOP_FRONT_RIGHT        0x4000
#define SPEAKER_TOP_BACK_LEFT          0x8000
#define SPEAKER_TOP_BACK_CENTER        0x10000
#define SPEAKER_TOP_BACK_RIGHT         0x20000
#define SPEAKER_RESERVED               0x80000000

//常量類
class Constants
{
public:
	Constants(void);
	~Constants(void);

	static const char *file_ext[];
	static const unsigned long srates[];
};

Constants.cpp

#include "stdafx.h"
#include "Constants.h"

Constants::Constants(void)
{
}

Constants::~Constants(void)
{
}

const char* Constants::file_ext[] =
{
	NULL,
	".wav",
	".aif",
	".au",
	".au",
	".pcm",
	".m4a",
	NULL
};

const unsigned long Constants::srates[] =
{
	96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
	12000, 11025, 8000
};

2、audio.c

audio.c文件中主要是對音頻文件格式和內容的封裝,需要注意的是,C語言中的靜態函數只能在本文件中使用。在此將其封裝爲C++類Audio。

Audio.h

#pragma once

#define MAXWAVESIZE     4294967040LU

#define OUTPUT_WAV 1
#define OUTPUT_RAW 2

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;

class Audio
{
public:
	Audio();
	~Audio();

	static audio_file *open_audio_file(char *infile, int samplerate, int channels,
		int outputFormat, int fileType, long channelMask);
	static int write_audio_file(audio_file *aufile, void *sample_buffer, int samples, int offset);
	static void close_audio_file(audio_file *aufile);

private:
	static int write_wav_header(audio_file *aufile);
	static int write_wav_extensible_header(audio_file *aufile, long channelMask);
	static int write_audio_16bit(audio_file *aufile, void *sample_buffer,
		unsigned int samples);
	static int write_audio_24bit(audio_file *aufile, void *sample_buffer,
		unsigned int samples);
	static int write_audio_32bit(audio_file *aufile, void *sample_buffer,
		unsigned int samples);
	static int write_audio_float(audio_file *aufile, void *sample_buffer,
		unsigned int samples);
};

Audio.cpp

#include "stdafx.h"
#include "Audio.h"
#ifdef _WIN32
#include <io.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <math.h>
#include <neaacdec.h>


Audio::Audio()
{

}

Audio::~Audio()
{

}

audio_file* Audio::open_audio_file(char *infile, int samplerate, int channels,
								   int outputFormat, int fileType, long channelMask)
{
	audio_file *aufile = (audio_file *)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;
	case FAAD_FMT_24BIT:
		aufile->bits_per_sample = 24;
		break;
	case FAAD_FMT_32BIT:
	case FAAD_FMT_FLOAT:
		aufile->bits_per_sample = 32;
		break;
	default:
		if (aufile) free(aufile);
		return NULL;
	}

	if(infile[0] == '-')
	{
#ifdef _WIN32
		_setmode(_fileno(stdout), O_BINARY);
#endif
		aufile->sndfile = stdout;
		aufile->toStdio = 1;
	} else {
		aufile->toStdio = 0;
		aufile->sndfile = fopen(infile, "wb");
		//fopen_s(&aufile->sndfile, infile, "wb");
	}

	if (aufile->sndfile == NULL)
	{
		if (aufile) free(aufile);
		return NULL;
	}

	if (aufile->fileType == OUTPUT_WAV)
	{
		if (aufile->channelMask)
			write_wav_extensible_header(aufile, aufile->channelMask);
		else
			write_wav_header(aufile);
	}

	return aufile;
}

int Audio::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);
	case FAAD_FMT_24BIT:
		return write_audio_24bit(aufile, buf + offset*4, samples);
	case FAAD_FMT_32BIT:
		return write_audio_32bit(aufile, buf + offset*4, samples);
	case FAAD_FMT_FLOAT:
		return write_audio_float(aufile, buf + offset*4, samples);
	default:
		return 0;
	}

	return 0;
}

void Audio::close_audio_file(audio_file *aufile)
{
	if ((aufile->fileType == OUTPUT_WAV) && (aufile->toStdio == 0))
	{
		fseek(aufile->sndfile, 0, SEEK_SET);

		if (aufile->channelMask)
			write_wav_extensible_header(aufile, aufile->channelMask);
		else
			write_wav_header(aufile);
	}

	if (aufile->toStdio == 0)
		fclose(aufile->sndfile);

	if (aufile) free(aufile);
}

int Audio::write_wav_header(audio_file *aufile)
{
	unsigned char header[44];
	unsigned char* p = header;
	unsigned int bytes = (aufile->bits_per_sample + 7) / 8;
	float data_size = (float)bytes * aufile->total_samples;
	unsigned long word32;

	*p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F';

	word32 = (data_size + (44 - 8) < (float)MAXWAVESIZE) ?
		(unsigned long)data_size + (44 - 8)  :  (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	*p++ = 'W'; *p++ = 'A'; *p++ = 'V'; *p++ = 'E';

	*p++ = 'f'; *p++ = 'm'; *p++ = 't'; *p++ = ' ';

	*p++ = 0x10; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;

	if (aufile->outputFormat == FAAD_FMT_FLOAT)
	{
		*p++ = 0x03; *p++ = 0x00;
	} else {
		*p++ = 0x01; *p++ = 0x00;
	}

	*p++ = (unsigned char)(aufile->channels >> 0);
	*p++ = (unsigned char)(aufile->channels >> 8);

	word32 = (unsigned long)(aufile->samplerate + 0.5);
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = aufile->samplerate * bytes * aufile->channels;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = bytes * aufile->channels;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);

	*p++ = (unsigned char)(aufile->bits_per_sample >> 0);
	*p++ = (unsigned char)(aufile->bits_per_sample >> 8);

	*p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a';

	word32 = data_size < MAXWAVESIZE ?
		(unsigned long)data_size : (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	return fwrite(header, sizeof(header), 1, aufile->sndfile);
}

int Audio::write_wav_extensible_header(audio_file *aufile, long channelMask)
{
	unsigned char header[68];
	unsigned char* p = header;
	unsigned int bytes = (aufile->bits_per_sample + 7) / 8;
	float data_size = (float)bytes * aufile->total_samples;
	unsigned long word32;

	*p++ = 'R'; *p++ = 'I'; *p++ = 'F'; *p++ = 'F';

	word32 = (data_size + (68 - 8) < (float)MAXWAVESIZE) ?
		(unsigned long)data_size + (68 - 8)  :  (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	*p++ = 'W'; *p++ = 'A'; *p++ = 'V'; *p++ = 'E';

	*p++ = 'f'; *p++ = 'm'; *p++ = 't'; *p++ = ' ';

	*p++ = /*0x10*/0x28; *p++ = 0x00; *p++ = 0x00; *p++ = 0x00;

	/* WAVE_FORMAT_EXTENSIBLE */
	*p++ = 0xFE; *p++ = 0xFF;

	*p++ = (unsigned char)(aufile->channels >> 0);
	*p++ = (unsigned char)(aufile->channels >> 8);

	word32 = (unsigned long)(aufile->samplerate + 0.5);
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = aufile->samplerate * bytes * aufile->channels;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	word32 = bytes * aufile->channels;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);

	*p++ = (unsigned char)(aufile->bits_per_sample >> 0);
	*p++ = (unsigned char)(aufile->bits_per_sample >> 8);

	/* cbSize */
	*p++ = (unsigned char)(22);
	*p++ = (unsigned char)(0);

	/* WAVEFORMATEXTENSIBLE */

	/* wValidBitsPerSample */
	*p++ = (unsigned char)(aufile->bits_per_sample >> 0);
	*p++ = (unsigned char)(aufile->bits_per_sample >> 8);

	/* dwChannelMask */
	word32 = channelMask;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	/* SubFormat */
	if (aufile->outputFormat == FAAD_FMT_FLOAT)
	{
		/* KSDATAFORMAT_SUBTYPE_IEEE_FLOAT: 00000003-0000-0010-8000-00aa00389b71 */
		*p++ = 0x03;
		*p++ = 0x00;
		*p++ = 0x00;
		*p++ = 0x00;
		*p++ = 0x00; *p++ = 0x00; *p++ = 0x10; *p++ = 0x00; *p++ = 0x80; *p++ = 0x00;
		*p++ = 0x00; *p++ = 0xaa; *p++ = 0x00; *p++ = 0x38; *p++ = 0x9b; *p++ = 0x71;
	} else {
		/* KSDATAFORMAT_SUBTYPE_PCM: 00000001-0000-0010-8000-00aa00389b71 */
		*p++ = 0x01;
		*p++ = 0x00;
		*p++ = 0x00;
		*p++ = 0x00;
		*p++ = 0x00; *p++ = 0x00; *p++ = 0x10; *p++ = 0x00; *p++ = 0x80; *p++ = 0x00;
		*p++ = 0x00; *p++ = 0xaa; *p++ = 0x00; *p++ = 0x38; *p++ = 0x9b; *p++ = 0x71;
	}

	/* end WAVEFORMATEXTENSIBLE */

	*p++ = 'd'; *p++ = 'a'; *p++ = 't'; *p++ = 'a';

	word32 = data_size < MAXWAVESIZE ?
		(unsigned long)data_size : (unsigned long)MAXWAVESIZE;
	*p++ = (unsigned char)(word32 >>  0);
	*p++ = (unsigned char)(word32 >>  8);
	*p++ = (unsigned char)(word32 >> 16);
	*p++ = (unsigned char)(word32 >> 24);

	return fwrite(header, sizeof(header), 1, aufile->sndfile);
}

int Audio::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 = (char *)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 Audio::write_audio_24bit(audio_file *aufile, void *sample_buffer,
							 unsigned int samples)
{
	int ret;
	unsigned int i;
	long *sample_buffer24 = (long*)sample_buffer;
	char *data = (char *)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)
		{
			long r1, r2, r3, r4, r5, r6;
			r1 = sample_buffer24[i];
			r2 = sample_buffer24[i+1];
			r3 = sample_buffer24[i+2];
			r4 = sample_buffer24[i+3];
			r5 = sample_buffer24[i+4];
			r6 = sample_buffer24[i+5];
			sample_buffer24[i] = r2;
			sample_buffer24[i+1] = r3;
			sample_buffer24[i+2] = r1;
			sample_buffer24[i+3] = r6;
			sample_buffer24[i+4] = r4;
			sample_buffer24[i+5] = r5;
		}
	}

	for (i = 0; i < samples; i++)
	{
		data[i*3] = (char)(sample_buffer24[i] & 0xFF);
		data[i*3+1] = (char)((sample_buffer24[i] >> 8) & 0xFF);
		data[i*3+2] = (char)((sample_buffer24[i] >> 16) & 0xFF);
	}

	ret = fwrite(data, samples, aufile->bits_per_sample/8, aufile->sndfile);

	if (data) free(data);

	return ret;
}

int Audio::write_audio_32bit(audio_file *aufile, void *sample_buffer,
							 unsigned int samples)
{
	int ret;
	unsigned int i;
	long *sample_buffer32 = (long*)sample_buffer;
	char *data = (char *)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)
		{
			long r1, r2, r3, r4, r5, r6;
			r1 = sample_buffer32[i];
			r2 = sample_buffer32[i+1];
			r3 = sample_buffer32[i+2];
			r4 = sample_buffer32[i+3];
			r5 = sample_buffer32[i+4];
			r6 = sample_buffer32[i+5];
			sample_buffer32[i] = r2;
			sample_buffer32[i+1] = r3;
			sample_buffer32[i+2] = r1;
			sample_buffer32[i+3] = r6;
			sample_buffer32[i+4] = r4;
			sample_buffer32[i+5] = r5;
		}
	}

	for (i = 0; i < samples; i++)
	{
		data[i*4] = (char)(sample_buffer32[i] & 0xFF);
		data[i*4+1] = (char)((sample_buffer32[i] >> 8) & 0xFF);
		data[i*4+2] = (char)((sample_buffer32[i] >> 16) & 0xFF);
		data[i*4+3] = (char)((sample_buffer32[i] >> 24) & 0xFF);
	}

	ret = fwrite(data, samples, aufile->bits_per_sample/8, aufile->sndfile);

	if (data) free(data);

	return ret;
}

int Audio::write_audio_float(audio_file *aufile, void *sample_buffer,
							 unsigned int samples)
{
	int ret;
	unsigned int i;
	float *sample_buffer_f = (float*)sample_buffer;
	unsigned char *data = (unsigned char *)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)
		{
			float r1, r2, r3, r4, r5, r6;
			r1 = sample_buffer_f[i];
			r2 = sample_buffer_f[i+1];
			r3 = sample_buffer_f[i+2];
			r4 = sample_buffer_f[i+3];
			r5 = sample_buffer_f[i+4];
			r6 = sample_buffer_f[i+5];
			sample_buffer_f[i] = r2;
			sample_buffer_f[i+1] = r3;
			sample_buffer_f[i+2] = r1;
			sample_buffer_f[i+3] = r6;
			sample_buffer_f[i+4] = r4;
			sample_buffer_f[i+5] = r5;
		}
	}

	for (i = 0; i < samples; i++)
	{
		int exponent, mantissa, negative = 0 ;
		float in = sample_buffer_f[i];

		data[i*4] = 0; data[i*4+1] = 0; data[i*4+2] = 0; data[i*4+3] = 0;
		if (in == 0.0)
			continue;

		if (in < 0.0)
		{
			in *= -1.0;
			negative = 1;
		}
		in = (float)frexp(in, &exponent);
		exponent += 126;
		in *= (float)0x1000000;
		mantissa = (((int)in) & 0x7FFFFF);

		if (negative)
			data[i*4+3] |= 0x80;

		if (exponent & 0x01)
			data[i*4+2] |= 0x80;

		data[i*4] = mantissa & 0xFF;
		data[i*4+1] = (mantissa >> 8) & 0xFF;
		data[i*4+2] |= (mantissa >> 16) & 0x7F;
		data[i*4+3] |= (exponent >> 1) & 0x7F;
	}

	ret = fwrite(data, samples, aufile->bits_per_sample/8, aufile->sndfile);

	if (data) free(data);

	return ret;
}

3、測試項目

操作步驟:

(1)創建MFC Dialog測試工程Faad2Test;

(2)將文件夾“faad2-2.7\libfaad”、"faad2-2.7\common\mp4ff"和“faad2-2.7\include”拷貝到工程文件夾下;

(3)添加現有項目libfaad.vcproj和mp4ff.vcproj到解決方案,提示項目的單向升級,選擇確定即可;

(4)設置libfaad和mp4ff的生成路徑爲..\Output\,然後依此修改輸出文件的路徑;

(5)爲Faad2Test設置項目依賴項;

(6)重新生成Faad2Test工程。

3.1 編譯錯誤:error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

解決方法:Faad2Test右鍵->屬性->配置屬性->C/C++->預處理器->預處理器定義,添加_CRT_SECURE_NO_WARNINGS預定義。

3.2 在Faad2Test添加libfaad.lib、mp4ff.lib依賴項。

3.3 測試代碼

	CString strAacPath;
	GetDlgItemText(IDC_EDIT_AAC, strAacPath);

	if (strAacPath.IsEmpty())
	{
		AfxMessageBox(_T("請選擇AAC文件"));
		return;
	}

	wstring waacPath(strAacPath.GetBuffer());
	string aacPath = CodeConverter::UnicodeToAcsii(waacPath);
	string wavPath;
	bool ret = CFaad2Proxy::GetInstance().TransAacToWav(aacPath, wavPath);
	if (ret)
	{
		CString strWavPath(wavPath.c_str());
		SetDlgItemText(IDC_EDIT_WAV, strWavPath);
		AfxMessageBox(_T("AAC轉碼WAV成功"));
	}
	else
	{
		string errMsg = CFaad2Proxy::GetInstance().GetLastError();
		CString strErrMsg;
		strErrMsg.Format(_T("AAC轉碼WAV失敗:\n%s"), errMsg.c_str());
		AfxMessageBox(strErrMsg);
	}
4、寫在最後

(1)faad2-2.7下載地址:官網 |百度網盤

(2)測試工程下載地址:CSDN |百度網盤

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章