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、寫在最後