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_C