[[PageNavi(NavigationList)]]
==== 付録:変更を加えたあとのfaacのソースコード ====
====== リスト1 並列化版faacのmain()関数 ======
{{{
int main(int argc, char *argv[])
{
int frames, currentFrame;
faacEncHandle hEncoder[_THREADS];
pcmfile_t *infile = NULL;
unsigned long samplesInput, maxBytesOutput, totalBytesWritten=0;
faacEncConfigurationPtr myFormat;
unsigned int mpegVersion = MPEG2;
unsigned int objectType = LOW;
unsigned int useMidSide = 1;
static unsigned int useTns = DEFAULT_TNS;
enum container_format container = NO_CONTAINER;
int optimizeFlag = 0;
enum stream_format stream = ADTS_STREAM;
int cutOff = -1;
int bitRate = 0;
unsigned long quantqual = 0;
int chanC = 3;
int chanLF = 4;
char *audioFileName = NULL;
char *aacFileName = NULL;
char *aacFileExt = NULL;
int aacFileNameGiven = 0;
float *pcmbuf;
int *chanmap = NULL;
unsigned char *bitbuf;
int samplesRead = 0;
const char *dieMessage = NULL;
int rawChans = 0; // disabled by default
int rawBits = 16;
int rawRate = 44100;
int rawEndian = 1;
int shortctl = SHORTCTL_NORMAL;
FILE *outfile = NULL;
int seq_read = 0;
int seq_write = 0;
int nLp;
#ifdef HAVE_LIBMP4V2
MP4FileHandle MP4hFile = MP4_INVALID_FILE_HANDLE;
MP4TrackId MP4track = 0;
unsigned int ntracks = 0, trackno = 0;
unsigned int ndiscs = 0, discno = 0;
u_int8_t compilation = 0;
const char *artist = NULL, *title = NULL, *album = NULL, *year = NULL,
*genre = NULL, *comment = NULL, *writer = NULL;
u_int8_t *art = NULL;
u_int64_t artSize = 0;
u_int64_t total_samples = 0;
u_int64_t encoded_samples = 0;
unsigned int delay_samples;
unsigned int frameSize;
#endif
char *faac_id_string;
char *faac_copyright_string;
#ifndef _WIN32
// install signal handler
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
#endif
// get faac version
if (faacEncGetVersion(faac_id_string,faac_copyright_string) == FAAC_CFG_VERSION)
{
fprintf(stderr, "Freeware Advanced Audio Coder\nFAAC %s\n\n", faac_id_string);
}
else
{
fprintf(stderr, __FILE__ "(%d): wrong libfaac version\n", __LINE__);
return 1;
}
/* begin process command line */
progName = argv[0];
while (1) {
static struct option long_options[] = {
{ "help", 0, 0, 'h'},
{ "long-help", 0, 0, 'H'},
{ "raw", 0, 0, 'r'},
{ "no-midside", 0, 0, NO_MIDSIDE_FLAG},
{ "cutoff", 1, 0, 'c'},
{ "quality", 1, 0, 'q'},
{ "pcmraw", 0, 0, 'P'},
{ "pcmsamplerate", 1, 0, 'R'},
{ "pcmsamplebits", 1, 0, 'B'},
{ "pcmchannels", 1, 0, 'C'},
{ "shortctl", 1, 0, SHORTCTL_FLAG},
{ "tns", 0, 0, TNS_FLAG},
{ "no-tns", 0, 0, NO_TNS_FLAG},
{ "mpeg-version", 1, 0, MPEGVERS_FLAG},
{ "obj-type", 1, 0, OBJTYPE_FLAG},
{ "license", 0, 0, 'L'},
#ifdef HAVE_LIBMP4V2
{ "createmp4", 0, 0, 'w'},
{ "optimize", 0, 0, 's'},
{ "artist", 1, 0, ARTIST_FLAG},
{ "title", 1, 0, TITLE_FLAG},
{ "album", 1, 0, ALBUM_FLAG},
{ "track", 1, 0, TRACK_FLAG},
{ "disc", 1, 0, DISC_FLAG},
{ "genre", 1, 0, GENRE_FLAG},
{ "year", 1, 0, YEAR_FLAG},
{ "cover-art", 1, 0, COVER_ART_FLAG},
{ "comment", 1, 0, COMMENT_FLAG},
{ "writer", 1, 0, WRITER_FLAG},
{ "compilation", 0, 0, COMPILATION_FLAG},
#endif
{ "pcmswapbytes", 0, 0, 'X'},
{ 0, 0, 0, 0}
};
int c = -1;
int option_index = 0;
c = getopt_long(argc, argv, "Hhb:m:o:rnc:q:PR:B:C:I:X"
#ifdef HAVE_LIBMP4V2
"ws"
#endif
,long_options,option_index);
if (c == -1)
break;
if (!c)
{
dieMessage = usage;
break;
}
switch (c) {
case 'o':
{
int l = strlen(optarg);
aacFileName = malloc(l+1);
memcpy(aacFileName, optarg, l);
aacFileName[l] = '\0';
aacFileNameGiven = 1;
}
break;
case 'r': {
stream = RAW_STREAM;
break;
}
case NO_MIDSIDE_FLAG: {
useMidSide = 0;
break;
}
case 'c': {
unsigned int i;
if (sscanf(optarg, "%u",i) 0) {
cutOff = i;
}
break;
}
case 'b': {
unsigned int i;
if (sscanf(optarg, "%u",i) 0)
{
bitRate = 1000 * i;
}
break;
}
case 'q':
{
unsigned int i;
if (sscanf(optarg, "%u",i) 0)
{
if (i 0 i 1000)
quantqual = i;
}
break;
}
case 'I':
sscanf(optarg, "%d,%d",chanC,chanLF);
break;
case 'P':
rawChans = 2; // enable raw input
break;
case 'R':
{
unsigned int i;
if (sscanf(optarg, "%u",i) 0)
{
rawRate = i;
rawChans = (rawChans 0) ? rawChans : 2;
}
break;
}
case 'B':
{
unsigned int i;
if (sscanf(optarg, "%u",i) 0)
{
if (i 32)
i = 32;
if (i 8)
i = 8;
rawBits = i;
rawChans = (rawChans 0) ? rawChans : 2;
}
break;
}
case 'C':
{
unsigned int i;
if (sscanf(optarg, "%u",i) 0)
rawChans = i;
break;
}
#ifdef HAVE_LIBMP4V2
case 'w':
container = MP4_CONTAINER;
break;
case 's':
optimizeFlag = 1;
break;
case ARTIST_FLAG:
artist = optarg;
break;
case WRITER_FLAG:
writer = optarg;
break;
case TITLE_FLAG:
title = optarg;
break;
case ALBUM_FLAG:
album = optarg;
break;
case TRACK_FLAG:
sscanf(optarg, "%d/%d",trackno,ntracks);
break;
case DISC_FLAG:
sscanf(optarg, "%d/%d",discno,ndiscs);
break;
case COMPILATION_FLAG:
compilation = 0x1;
break;
case GENRE_FLAG:
genre = optarg;
break;
case YEAR_FLAG:
year = optarg;
break;
case COMMENT_FLAG:
comment = optarg;
break;
case COVER_ART_FLAG: {
FILE *artFile = fopen(optarg, "rb");
if(artFile) {
u_int64_t r;
fseek(artFile, 0, SEEK_END);
artSize = ftell(artFile);
art = malloc(artSize);
fseek(artFile, 0, SEEK_SET);
clearerr(artFile);
r = fread(art, artSize, 1, artFile);
if (r != 1) {
dieMessage = "Error reading cover art file!\n";
free(art);
art = NULL;
} else if (artSize 12 || !check_image_header(art)) {
/* the above expression checks the image signature */
dieMessage = "Unsupported cover image file format!\n";
free(art);
art = NULL;
}
fclose(artFile);
} else {
dieMessage = "Error opening cover art file!\n";
}
break;
}
#endif
case SHORTCTL_FLAG:
shortctl = atoi(optarg);
break;
case TNS_FLAG:
useTns = 1;
break;
case NO_TNS_FLAG:
useTns = 0;
break;
case MPEGVERS_FLAG:
mpegVersion = atoi(optarg);
switch(mpegVersion)
{
case 2:
mpegVersion = MPEG2;
break;
case 4:
mpegVersion = MPEG4;
break;
default:
dieMessage = "Unrecognised MPEG version!\n";
}
break;
#if 0
case OBJTYPE_FLAG:
if (!strcasecmp(optarg, "LC"))
objectType = LOW;
else if (!strcasecmp(optarg, "Main"))
objectType = MAIN;
else if (!strcasecmp(optarg, "LTP")) {
mpegVersion = MPEG4;
objectType = LTP;
} else
dieMessage = "Unrecognised object type!\n";
break;
#endif
case 'L':
fprintf(stderr, faac_copyright_string);
dieMessage = license;
break;
case 'X':
rawEndian = 0;
break;
case 'H':
dieMessage = long_help;
break;
case 'h':
dieMessage = short_help;
break;
case '?':
default:
dieMessage = usage;
break;
}
}
/* check that we have at least one non-option arguments */
if (!dieMessage (argc - optind) 1 aacFileNameGiven)
dieMessage = "Cannot encode several input files to one output file.\n";
if (argc - optind 1 || dieMessage)
{
fprintf(stderr, dieMessage ? dieMessage : usage,
progName, progName, progName, progName);
return 1;
}
while (argc - optind 0) {
/* get the input file name */
audioFileName = argv[optind++];
/* generate the output file name, if necessary */
if (!aacFileNameGiven) {
char *t = strrchr(audioFileName, '.');
int l = t ? strlen(audioFileName) - strlen(t) : strlen(audioFileName);
#ifdef HAVE_LIBMP4V2
aacFileExt = container == MP4_CONTAINER ? ".m4a" : ".aac";
#else
aacFileExt = ".aac";
#endif
aacFileName = malloc(l+1+4);
memcpy(aacFileName, audioFileName, l);
memcpy(aacFileName + l, aacFileExt, 4);
aacFileName[l+4] = '\0';
} else {
aacFileExt = strrchr(aacFileName, '.');
if (aacFileExt (!strcmp(".m4a", aacFileExt) || !strcmp(".m4b", aacFileExt) || !strcmp(".mp4", aacFileExt)))
#ifndef HAVE_LIBMP4V2
fprintf(stderr, "WARNING: MP4 support unavailable!\n");
#else
container = MP4_CONTAINER;
#endif
}
/* open the audio input file */
if (rawChans 0) // use raw input
{
infile = wav_open_read(audioFileName, 1);
if (infile)
{
infile-bigendian = rawEndian;
infile-channels = rawChans;
infile-samplebytes = rawBits / 8;
infile-samplerate = rawRate;
infile-samples /= (infile-channels * infile-samplebytes);
}
}
else // header input
infile = wav_open_read(audioFileName, 0);
if (infile == NULL)
{
fprintf(stderr, "Couldn't open input file %s\n", audioFileName);
return 1;
}
/* open the encoder library */
for(nLp = 0; nLp _THREADS; nLp++) {
hEncoder[nLp] = faacEncOpen(infile-samplerate, infile-channels,samplesInput,maxBytesOutput);
}
#ifdef HAVE_LIBMP4V2
if (container != MP4_CONTAINER (ntracks || trackno || artist ||
title || album || year || art ||
genre || comment || discno || ndiscs ||
writer || compilation))
{
fprintf(stderr, "Metadata requires MP4 output!\n");
return 1;
}
if (container == MP4_CONTAINER)
{
mpegVersion = MPEG4;
stream = RAW_STREAM;
}
frameSize = samplesInput/infile-channels;
delay_samples = frameSize; // encoder delay 1024 samples
#endif
/*
pcmbuf = (float *)malloc(samplesInput*sizeof(float));
bitbuf = (unsigned char*)malloc(maxBytesOutput*sizeof(unsigned char));
chanmap = mkChanMap(infile-channels, chanC, chanLF);
if (chanmap)
{
fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n",
chanC, chanLF);
}
*/
if (cutOff= 0)
{
if (cutOff 0) // default
cutOff = 0;
else // disabled
cutOff = infile-samplerate / 2;
}
if (cutOff (infile-samplerate / 2))
cutOff = infile-samplerate / 2;
/* put the options in the configuration struct */
myFormat = faacEncGetCurrentConfiguration(hEncoder[0]);
myFormat-aacObjectType = objectType;
myFormat-mpegVersion = mpegVersion;
myFormat-useTns = useTns;
switch (shortctl)
{
case SHORTCTL_NOSHORT:
fprintf(stderr, "disabling short blocks\n");
myFormat-shortctl = shortctl;
break;
case SHORTCTL_NOLONG:
fprintf(stderr, "disabling long blocks\n");
myFormat-shortctl = shortctl;
break;
}
if (infile-channels= 6)
myFormat-useLfe = 1;
myFormat-allowMidside = useMidSide;
if (bitRate)
myFormat-bitRate = bitRate / infile-channels;
myFormat-bandWidth = cutOff;
if (quantqual 0)
myFormat-quantqual = quantqual;
myFormat-outputFormat = stream;
myFormat-inputFormat = FAAC_INPUT_FLOAT;
if (!faacEncSetConfiguration(hEncoder[0], myFormat)) {
fprintf(stderr, "Unsupported output format!\n");
#ifdef HAVE_LIBMP4V2
if (container == MP4_CONTAINER) MP4Close(MP4hFile);
#endif
return 1;
}
for(nLp = 1; nLp _THREADS; nLp++) {
faacEncSetConfiguration(hEncoder[nLp], myFormat);
}
#ifdef HAVE_LIBMP4V2
/* initialize MP4 creation */
if (container == MP4_CONTAINER) {
unsigned char *ASC = 0;
unsigned long ASCLength = 0;
char *version_string;
#ifdef MP4_CREATE_EXTENSIBLE_FORMAT
/* hack to compile against libmp4v2= 1.0RC3
* why is there no version identifier in mp4.h? */
MP4hFile = MP4Create(aacFileName, MP4_DETAILS_ERROR, 0);
#else
MP4hFile = MP4Create(aacFileName, MP4_DETAILS_ERROR, 0, 0);
#endif
if (!MP4_IS_VALID_FILE_HANDLE(MP4hFile)) {
fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
return 1;
}
MP4SetTimeScale(MP4hFile, 90000);
MP4track = MP4AddAudioTrack(MP4hFile, infile-samplerate, MP4_INVALID_DURATION, MP4_MPEG4_AUDIO_TYPE);
MP4SetAudioProfileLevel(MP4hFile, 0x0F);
faacEncGetDecoderSpecificInfo(hEncoder[0],ASC,ASCLength);
MP4SetTrackESConfiguration(MP4hFile, MP4track, ASC, ASCLength);
free(ASC);
/* set metadata */
version_string = malloc(strlen(faac_id_string) + 6);
strcpy(version_string, "FAAC ");
strcpy(version_string + 5, faac_id_string);
MP4SetMetadataTool(MP4hFile, version_string);
free(version_string);
if (artist) MP4SetMetadataArtist(MP4hFile, artist);
if (writer) MP4SetMetadataWriter(MP4hFile, writer);
if (title) MP4SetMetadataName(MP4hFile, title);
if (album) MP4SetMetadataAlbum(MP4hFile, album);
if (trackno 0) MP4SetMetadataTrack(MP4hFile, trackno, ntracks);
if (discno 0) MP4SetMetadataDisk(MP4hFile, discno, ndiscs);
if (compilation) MP4SetMetadataCompilation(MP4hFile, compilation);
if (year) MP4SetMetadataYear(MP4hFile, year);
if (genre) MP4SetMetadataGenre(MP4hFile, genre);
if (comment) MP4SetMetadataComment(MP4hFile, comment);
if (artSize) {
MP4SetMetadataCoverArt(MP4hFile, art, artSize);
free(art);
}
}
else
{
#endif
/* open the aac output file */
if (!strcmp(aacFileName, "-"))
{
outfile = stdout;
}
else
{
outfile = fopen(aacFileName, "wb");
}
if (!outfile)
{
fprintf(stderr, "Couldn't create output file %s\n", aacFileName);
return 1;
}
#ifdef HAVE_LIBMP4V2
}
#endif
cutOff = myFormat-bandWidth;
quantqual = myFormat-quantqual;
bitRate = myFormat-bitRate;
if (bitRate)
fprintf(stderr, "Average bitrate: %d kbps\n",
(bitRate + 500)/1000*infile-channels);
fprintf(stderr, "Quantization quality: %ld\n", quantqual);
fprintf(stderr, "Bandwidth: %d Hz\n", cutOff);
fprintf(stderr, "Object type: ");
switch(objectType)
{
case LOW:
fprintf(stderr, "Low Complexity");
break;
case MAIN:
fprintf(stderr, "Main");
break;
case LTP:
fprintf(stderr, "LTP");
break;
}
fprintf(stderr, "(MPEG-%d)", (mpegVersion == MPEG4) ? 4 : 2);
if (myFormat-useTns)
fprintf(stderr, " + TNS");
if (myFormat-allowMidside)
fprintf(stderr, " + M/S");
fprintf(stderr, "\n");
fprintf(stderr, "Container format: ");
switch(container)
{
case NO_CONTAINER:
switch(stream)
{
case RAW_STREAM:
fprintf(stderr, "Headerless AAC (RAW)\n");
break;
case ADTS_STREAM:
fprintf(stderr, "Transport Stream (ADTS)\n");
break;
}
break;
#ifdef HAVE_LIBMP4V2
case MP4_CONTAINER:
fprintf(stderr, "MPEG-4 File Format (MP4)\n");
break;
#endif
}
if (outfile
#ifdef HAVE_LIBMP4V2
|| MP4hFile != MP4_INVALID_FILE_HANDLE
#endif
)
{
int showcnt = 0;
#ifdef _WIN32
long begin = GetTickCount();
#endif
if (infile-samples)
frames = ((infile-samples + 1023) / 1024) + 1;
else
frames = 0;
currentFrame = 0;
fprintf(stderr, "Encoding %s to %s\n", audioFileName, aacFileName);
if (frames != 0)
fprintf(stderr, " frame | bitrate | elapsed/estim | "
"play/CPU | ETA\n");
else
fprintf(stderr, " frame | elapsed | play/CPU\n");
/* encoding loop */
/* ループここから */
omp_set_num_threads(_THREADS); /* 2スレッド使用 */
/* begin OpenMP */
#pragma omp parallel private(samplesRead, pcmbuf, bitbuf, chanmap) firstprivate(samplesInput)
{
int _THREAD_ID;
int seq = 0;
_THREAD_ID = omp_get_thread_num();
pcmbuf = (float *)malloc(samplesInput*sizeof(float));
bitbuf = (unsigned char*)malloc(maxBytesOutput*sizeof(unsigned char));
chanmap = mkChanMap(infile-channels, chanC, chanLF);
if (chanmap)
{
fprintf(stderr, "Remapping input channels: Center=%d, LFE=%d\n",
chanC, chanLF);
}
#ifdef _WIN32
for (;;)
#else
while (running)
#endif
{
int bytesWritten;
#pragma omp critical (sample_read)
{
samplesRead = wav_read_float32(infile, pcmbuf, samplesInput, chanmap);
seq = seq_read;
seq_read++;
#ifdef HAVE_LIBMP4V2
total_samples += samplesRead / infile-channels;
#endif
}
if(samplesRead == 0)
break;
/* call the actual encoding routine */
bytesWritten = faacEncEncode(hEncoder[_THREAD_ID],
(int32_t *)pcmbuf,
samplesRead,
bitbuf,
maxBytesOutput);
if (bytesWritten)
{
#pragma omp critical (inc_frames)
{
currentFrame++;
showcnt--;
totalBytesWritten += bytesWritten;
}
}
if ((showcnt= 0) || !bytesWritten)
{
double timeused;
#ifdef __unix__
struct rusage usage;
#endif
#ifdef _WIN32
char percent[MAX_PATH + 20];
timeused = (GetTickCount() - begin) * 1e-3;
#else
#ifdef __unix__
if (getrusage(RUSAGE_SELF,usage) == 0) {
timeused = (double)usage.ru_utime.tv_sec +
(double)usage.ru_utime.tv_usec * 1e-6;
}
else
timeused = 0;
#else
timeused = (double)clock() * (1.0 / CLOCKS_PER_SEC);
#endif
#endif
if (currentFrame (timeused 0.1))
{
#pragma omp critical (inccnt)
{
showcnt += 50;
}
if (frames != 0)
fprintf(stderr,
"\r%5d/%-5d (%3d%%)| %5.1f | %6.1f/%-6.1f | %7.2fx | %.1f ",
currentFrame, frames, currentFrame*100/frames,
((double)totalBytesWritten * 8.0 / 1000.0) /
((double)infile-samples / infile-samplerate * currentFrame / frames),
timeused,
timeused * frames / currentFrame,
(1024.0 * currentFrame / infile-samplerate) / timeused,
timeused * (frames - currentFrame) / currentFrame);
else
fprintf(stderr,
"\r %5d | %6.1f | %7.2fx ",
currentFrame,
timeused,
(1024.0 * currentFrame / infile-samplerate) / timeused);
fflush(stderr);
#ifdef _WIN32
if (frames != 0)
{
sprintf(percent, "%.2f%% encoding %s",
100.0 * currentFrame / frames, audioFileName);
SetConsoleTitle(percent);
}
#endif
}
}
/* all done, bail out */
if (!samplesRead !bytesWritten)
break ;
if (bytesWritten 0)
{
fprintf(stderr, "faacEncEncode() failed\n");
break ;
}
if (bytesWritten 0)
{
#ifdef HAVE_LIBMP4V2
u_int64_t samples_left = total_samples - encoded_samples + delay_samples;
MP4Duration dur = samples_left frameSize ? frameSize : samples_left;
MP4Duration ofs = encoded_samples 0 ? 0 : delay_samples;
if (container == MP4_CONTAINER)
{
/* write bitstream to mp4 file */
MP4WriteSample(MP4hFile, MP4track, bitbuf, bytesWritten, dur, ofs, 1);
}
else
{
#endif
/* write bitstream to aac file */
while(seq seq_write) {
#pragma omp flush(seq_write)
Sleep(0);
}
#pragma omp critical (write_aac)
{
fwrite(bitbuf, 1, bytesWritten, outfile);
seq_write++;
}
#ifdef HAVE_LIBMP4V2
}
#pragma omp critical (addsample)
{
encoded_samples += dur;
}
#endif
}
else
{
#pragma omp critical (write_aac)
{
seq_write++;
}
}
}
/* ループここまで */
if (pcmbuf) free(pcmbuf);
if (bitbuf) free(bitbuf);
} /* #pragma omp parallel */
#ifdef HAVE_LIBMP4V2
/* clean up */
if (container == MP4_CONTAINER)
{
MP4Close(MP4hFile);
if (optimizeFlag == 1)
{
fprintf(stderr, "\n\nMP4 format optimization... ");
MP4Optimize(aacFileName, NULL, 0);
fprintf(stderr, "Done!");
}
} else
#endif
fclose(outfile);
fprintf(stderr, "\n\n");
}
for(nLp = 0; nLp _THREADS; nLp++) {
faacEncClose(hEncoder[nLp]);
}
wav_close(infile);
/*
if (pcmbuf) free(pcmbuf);
if (bitbuf) free(bitbuf);
*/
if (aacFileNameGiven) free(aacFileName);
}
return 0;
}
}}}
[[PageNavi(NavigationList)]]