ref: c7dc7254c1ecfeb2227275f56bddac4f4e822760
dir: /frontend/main.c/
/* ** FAAD - Freeware Advanced Audio Decoder ** Copyright (C) 2002 M. Bakker ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ** ** $Id: main.c,v 1.1 2002/01/14 19:15:55 menno Exp $ **/ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include <windows.h> #else #include <time.h> #endif #include <stdio.h> #include <io.h> #include <fcntl.h> #include <stdlib.h> #include <getopt.h> #include <faad.h> #include <sndfile.h> #ifndef min #define min(a,b) ( (a) < (b) ? (a) : (b) ) #endif #define MAX_CHANNELS 6 /* make this higher to support files with more channels */ /* FAAD file buffering routines */ /* declare buffering variables */ #define DEC_BUFF_VARS \ int fileread, tagsize, bytesconsumed, k; \ int buffercount = 0, buffer_index = 0; \ unsigned char *buffer; /* initialise buffering */ #define INIT_BUFF(file) \ fseek(file, 0, SEEK_END); \ fileread = ftell(file); \ fseek(file, 0, SEEK_SET); \ buffer = (unsigned char*)malloc(FAAD_MIN_STREAMSIZE*MAX_CHANNELS); \ memset(buffer, 0, FAAD_MIN_STREAMSIZE*MAX_CHANNELS); \ fread(buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, file); /* skip bytes in buffer */ #define UPDATE_BUFF_SKIP(bytes) \ fseek(infile, bytes, SEEK_SET); \ buffer_index += bytes; \ buffercount = 0; \ fread(buffer, 1, FAAD_MIN_STREAMSIZE*MAX_CHANNELS, infile); /* update buffer */ #define UPDATE_BUFF_READ \ if (bytesconsumed > 0) { \ for (k = 0; k < (FAAD_MIN_STREAMSIZE*MAX_CHANNELS - bytesconsumed); k++) \ buffer[k] = buffer[k + bytesconsumed]; \ fread(buffer + (FAAD_MIN_STREAMSIZE*MAX_CHANNELS) - bytesconsumed, 1, bytesconsumed, infile); \ bytesconsumed = 0; \ } /* update buffer indices after faacDecDecode */ #define UPDATE_BUFF_IDX(frame) \ bytesconsumed += frame.bytesconsumed; \ buffer_index += frame.bytesconsumed; /* true if decoding has to stop because of EOF */ #define IS_FILE_END buffer_index >= fileread /* end buffering */ #define END_BUFF if (buffer) free(buffer); /* globals */ char *progName; int id3v2_tag(unsigned char *buffer) { if (strncmp(buffer, "ID3", 3) == 0) { unsigned long tagsize; /* high bit is not used */ tagsize = (buffer[6] << 21) | (buffer[7] << 14) | (buffer[8] << 7) | (buffer[9] << 0); tagsize += 10; return tagsize; } else { return 0; } } char *file_ext[] = { NULL, ".wav", ".aif", ".au", ".au", ".pcm", NULL }; void usage(void) { fprintf(stderr, "\nUsage:\n"); fprintf(stderr, "%s [options] infile.aac\n", progName); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h Shows this help screen.\n"); fprintf(stderr, " -o X Set output filename.\n"); fprintf(stderr, " -f X Set output format. Valid values for X are:\n"); fprintf(stderr, " 1: Microsoft WAV format (default).\n"); fprintf(stderr, " 2: Apple/SGI AIFF format.\n"); fprintf(stderr, " 3: Sun/NeXT AU format.\n"); fprintf(stderr, " 4: DEC AU format.\n"); fprintf(stderr, " 5: RAW PCM data.\n"); fprintf(stderr, " -b X Set output sample format. Valid values for X are:\n"); fprintf(stderr, " 1: 16 bit PCM data (default).\n"); fprintf(stderr, " 2: 24 bit PCM data.\n"); fprintf(stderr, " 3: 32 bit PCM data.\n"); fprintf(stderr, " 4: 32 bit floats.\n"); fprintf(stderr, " -s X Force the samplerate to X (for RAW files).\n"); fprintf(stderr, " -l Use Long Term Prediction (for RAW files).\n"); fprintf(stderr, " -w Write output to stdio instead of a file.\n"); fprintf(stderr, "Example:\n"); fprintf(stderr, " faad -o aac infile.aac\n"); return; } int main(int argc, char *argv[]) { void *sample_buffer; int writeToStdio = 0; int def_sr_set = 0; int use_ltp = 0; int def_srate; unsigned long samplerate, channels; int format = 1; int outputFormat = FAAD_FMT_16BIT; int outfile_set = 0; int showHelp = 0; char *fnp; char aacFileName[255]; char audioFileName[255]; SNDFILE *sndfile = NULL; SF_INFO sfinfo; FILE *infile; faacDecHandle hDecoder; faacDecFrameInfo frameInfo; faacDecConfigurationPtr config; char percents[200]; int percent, old_percent = -1; int first_time = 1; /* System dependant types */ #ifdef _WIN32 long begin, end; #else clock_t begin; #endif /* declare variables for buffering */ DEC_BUFF_VARS fprintf(stderr, "FAAD (Freeware AAC Decoder) Compiled on: " __DATE__ "\n"); fprintf(stderr, "Copyright: M. Bakker\n"); fprintf(stderr, " http://www.audiocoding.com\n\n"); /* begin process command line */ progName = argv[0]; while (1) { int c = -1; int option_index = 0; static struct option long_options[] = { { "outfile", 0, 0, 'o' }, { "format", 0, 0, 'f' }, { "bits", 0, 0, 'b' }, { "samplerate", 0, 0, 's' }, { "ltp", 0, 0, 'l' }, { "stdio", 0, 0, 'w' }, { "help", 0, 0, 'h' } }; c = getopt_long(argc, argv, "o:s:f:b:lwh", long_options, &option_index); if (c == -1) break; switch (c) { case 'o': if (optarg) { char dr[255]; if (sscanf(optarg, "%s", dr) < 1) { outfile_set = 0; } else { outfile_set = 1; strcpy(audioFileName, dr); } } break; case 's': if (optarg) { char dr[10]; if (sscanf(optarg, "%s", dr) < 1) { def_sr_set = 0; } else { def_sr_set = 1; def_srate = atoi(dr); } } break; case 'f': if (optarg) { char dr[10]; if (sscanf(optarg, "%s", dr) < 1) { format = 1; } else { format = atoi(dr); if ((format < 1) || (format > 5)) showHelp = 1; } } break; case 'b': if (optarg) { char dr[10]; if (sscanf(optarg, "%s", dr) < 1) { outputFormat = FAAD_FMT_16BIT; /* just use default */ } else { outputFormat = atoi(dr); if ((outputFormat < 1) || (outputFormat > 4)) showHelp = 1; } } break; case 'l': use_ltp = 1; break; case 'w': writeToStdio = 1; break; case 'h': showHelp = 1; break; default: break; } } /* check that we have at least two non-option arguments */ /* Print help if requested */ if (((argc - optind) < 1) || showHelp) { usage(); return 1; } /* point to the specified file name */ strcpy(aacFileName, argv[optind]); #ifdef _WIN32 begin = GetTickCount(); #else begin = clock(); #endif infile = fopen(aacFileName, "rb"); if (infile == NULL) { /* unable to open file */ fprintf(stderr, "Error opening file: %s\n", aacFileName); return 1; } INIT_BUFF(infile) tagsize = id3v2_tag(buffer); if (tagsize) { UPDATE_BUFF_SKIP(tagsize) } hDecoder = faacDecOpen(); /* Set the default object type and samplerate */ /* This is useful for RAW AAC files */ config = faacDecGetCurrentConfiguration(hDecoder); if (def_sr_set) config->defSampleRate = def_srate; if (use_ltp) config->defObjectType = LTP; config->outputFormat = outputFormat; faacDecSetConfiguration(hDecoder, config); if((bytesconsumed = faacDecInit(hDecoder, buffer, &samplerate, &channels)) < 0) { /* If some error initializing occured, skip the file */ fprintf(stderr, "Error initializing decoder library.\n"); END_BUFF faacDecClose(hDecoder); fclose(infile); return 1; } /* update buffer */ UPDATE_BUFF_READ /* Only calculate the path and open the file for writing if we are not writing to stdout. */ if(!writeToStdio && !outfile_set) { strcpy(audioFileName, aacFileName); fnp = (char *)strrchr(audioFileName,'.'); if (fnp) fnp[0] = '\0'; strcat(audioFileName, file_ext[format]); } do { /* update buffer */ UPDATE_BUFF_READ sample_buffer = faacDecDecode(hDecoder, &frameInfo, buffer); /* update buffer indices */ UPDATE_BUFF_IDX(frameInfo) if (frameInfo.error > 0) { fprintf(stderr, "Error: %s\n", faacDecGetErrorMessage(frameInfo.error)); } percent = min((int)(buffer_index*100)/fileread, 100); if (percent > old_percent) { old_percent = percent; sprintf(percents, "%d%% decoding %s.", percent, aacFileName); fprintf(stderr, "%s\r", percents); #ifdef _WIN32 SetConsoleTitle(percents); #endif } /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { sfinfo.samplerate = samplerate; switch (outputFormat) { case FAAD_FMT_16BIT: sfinfo.pcmbitwidth = 16; sfinfo.format = ((1<<(format+15)) | SF_FORMAT_PCM); break; case FAAD_FMT_24BIT: sfinfo.pcmbitwidth = 24; sfinfo.format = ((1<<(format+15)) | SF_FORMAT_PCM); break; case FAAD_FMT_32BIT: sfinfo.pcmbitwidth = 32; sfinfo.format = ((1<<(format+15)) | SF_FORMAT_PCM); break; case FAAD_FMT_FLOAT: sfinfo.pcmbitwidth = 32; sfinfo.format = ((1<<(format+15)) | SF_FORMAT_FLOAT); break; } sfinfo.channels = frameInfo.channels; sfinfo.samples = 0; if(!writeToStdio) { sndfile = sf_open_write(audioFileName, &sfinfo); } else { setmode(fileno(stdout), O_BINARY); sndfile = sf_open_write("-", &sfinfo); } if (sndfile == NULL) { sf_perror(NULL); END_BUFF faacDecClose(hDecoder); fclose(infile); return 1; } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { switch (outputFormat) { case FAAD_FMT_16BIT: sf_write_short(sndfile, (short*)sample_buffer, frameInfo.samples); break; case FAAD_FMT_24BIT: case FAAD_FMT_32BIT: sf_write_int(sndfile, (int*)sample_buffer, frameInfo.samples); break; case FAAD_FMT_FLOAT: sf_write_float(sndfile, (float*)sample_buffer, frameInfo.samples); break; } } if (IS_FILE_END) sample_buffer = NULL; /* to make sure it stops now */ } while (sample_buffer != NULL); faacDecClose(hDecoder); fclose(infile); if (sndfile) sf_close(sndfile); if (!frameInfo.error) { #ifdef _WIN32 end = GetTickCount(); fprintf(stderr, "Decoding %s took: %d sec.\n", aacFileName, (end-begin)/1000); SetConsoleTitle("FAAD"); #else /* clock() grabs time since the start of the app but when we decode multiple files, each file has its own starttime (begin). */ fprintf(stderr, "Decoding %s took: %5.2f sec.\n", aacFileName, (float)(clock() - begin)/(float)CLOCKS_PER_SEC); #endif } END_BUFF return 0; }