/* ** 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: decode.c,v 1.16 2004/04/03 19:08:37 menno Exp $ ** $Id: decode.c,v 1.16 2004/04/03 19:08:37 menno Exp $ **/ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include #define off_t __int64 #else #include #endif #include #include #include #include #include "audio.h" #include "decode.h" #include "misc.h" #include "wave_out.h" #ifndef min #define min(a,b) ( (a) < (b) ? (a) : (b) ) #endif #define MAX_CHANNELS 8 /* make this higher to support files with more channels */ /* FAAD file buffering routines */ /* declare buffering variables */ #define DEC_BUFF_VARS \ int fileread, bytesconsumed, k; \ int buffercount = 0, buffer_index = 0; \ unsigned char *buffer; \ unsigned int bytes_in_buffer = 0; /* 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); \ bytes_in_buffer = 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; \ bytes_in_buffer = 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]; \ bytes_in_buffer += fread(buffer + (FAAD_MIN_STREAMSIZE*MAX_CHANNELS) - bytesconsumed, 1, bytesconsumed, infile); \ bytesconsumed = 0; \ } /* update buffer indices after NeAACDecDecode */ #define UPDATE_BUFF_IDX(frame) \ bytesconsumed += frame.bytesconsumed; \ buffer_index += frame.bytesconsumed; \ bytes_in_buffer -= 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; extern int stop_decoding; 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", NULL }; /* 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 long 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; } } int decodeAACfile(char *sndfile, int def_srate, aac_dec_opt *opt) { int tagsize; unsigned long samplerate; unsigned char channels; void *sample_buffer; FILE *infile; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; NeAACDecConfigurationPtr config; int first_time = 1; /* declare variables for buffering */ DEC_BUFF_VARS infile = fopen(opt->filename, "rb"); if (infile == NULL) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } INIT_BUFF(infile) tagsize = id3v2_tag(buffer); if (tagsize) { UPDATE_BUFF_SKIP(tagsize) } 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 = opt->object_type; config->outputFormat = opt->output_format; NeAACDecSetConfiguration(hDecoder, config); if ((bytesconsumed = NeAACDecInit(hDecoder, buffer, bytes_in_buffer, &samplerate, &channels)) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 1; } buffer_index += bytesconsumed; do { /* update buffer */ UPDATE_BUFF_READ sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, bytes_in_buffer); /* update buffer indices */ UPDATE_BUFF_IDX(frameInfo) if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); } opt->progress_update((long)fileread, buffer_index); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); END_BUFF NeAACDecClose(hDecoder); fclose(infile); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { END_BUFF NeAACDecClose(hDecoder); fclose(infile); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (buffer_index >= fileread) sample_buffer = NULL; /* to make sure it stops now */ if(stop_decoding) break; } while (sample_buffer != NULL); NeAACDecClose(hDecoder); fclose(infile); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } END_BUFF return frameInfo.error; } int 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, &buff_size); if (buff) { rc = NeAACDecAudioSpecificConfig(buff, buff_size, &mp4ASC); free(buff); if (rc < 0) continue; return i; } } /* can't decode this */ return -1; } unsigned long srates[] = { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000 }; uint32_t read_callback(void *user_data, void *buffer, uint32_t length) { return fread(buffer, 1, length, (FILE*)user_data); } uint32_t seek_callback(void *user_data, uint64_t position) { return fseek((FILE*)user_data, position, SEEK_SET); } int decodeMP4file(char *sndfile, aac_dec_opt *opt) { int track; unsigned long samplerate; unsigned char channels; void *sample_buffer; mp4ff_t *infile; FILE *mp4File; int sampleId, numSamples; audio_file *aufile; NeAACDecHandle hDecoder; NeAACDecFrameInfo frameInfo; unsigned char *buffer; int buffer_size; int first_time = 1; /* initialise the callback structure */ mp4ff_callback_t *mp4cb = malloc(sizeof(mp4ff_callback_t)); mp4File = fopen(opt->filename, "rb"); mp4cb->read = read_callback; mp4cb->seek = seek_callback; mp4cb->user_data = mp4File; infile = mp4ff_open_read(mp4cb); if (!infile) { /* unable to open file */ error_handler("Error opening file: %s\n", opt->filename); return 1; } if ((track = GetAACTrack(infile)) < 0) { error_handler("Unable to find correct AAC sound track in the MP4 file.\n"); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } buffer = NULL; buffer_size = 0; mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); hDecoder = NeAACDecOpen(); if(NeAACDecInit2(hDecoder, buffer, buffer_size, &samplerate, &channels) < 0) { /* If some error initializing occured, skip the file */ error_handler("Error initializing decoder library.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } if (buffer) free(buffer); numSamples = mp4ff_num_samples(infile, track); for (sampleId = 0; sampleId < numSamples; sampleId++) { int rc; /* get access unit from MP4 file */ buffer = NULL; buffer_size = 0; rc = mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size); if (rc == 0) { error_handler("Reading from MP4 file failed.\n"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 1; } sample_buffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, buffer_size); if (buffer) free(buffer); opt->progress_update((long)numSamples, sampleId); /* open the sound file now that the number of channels are known */ if (first_time && !frameInfo.error) { if(opt->decode_mode == 0) { if (Set_WIN_Params (INVALID_FILEDESC, samplerate, SAMPLE_SIZE, frameInfo.channels) < 0) { error_handler("\nCan't access %s\n", "WAVE OUT"); NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return (0); } } else { aufile = open_audio_file(sndfile, samplerate, frameInfo.channels, opt->output_format, opt->file_type, aacChannelConfig2wavexChannelMask(&frameInfo)); if (aufile == NULL) { NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); return 0; } } first_time = 0; } if ((frameInfo.error == 0) && (frameInfo.samples > 0)) { if(opt->decode_mode == 0) WIN_Play_Samples((short*)sample_buffer, frameInfo.channels*frameInfo.samples); else write_audio_file(aufile, sample_buffer, frameInfo.samples, 0); } if (frameInfo.error > 0) { error_handler("Error: %s\n", NeAACDecGetErrorMessage(frameInfo.error)); break; } if(stop_decoding) break; } NeAACDecClose(hDecoder); mp4ff_close(infile); free(mp4cb); fclose(mp4File); if(opt->decode_mode == 0) WIN_Audio_close(); else { if (!first_time) close_audio_file(aufile); } return frameInfo.error; } int str_no_case_comp(char const *str1, char const *str2, unsigned long len) { signed int c1 = 0, c2 = 0; while (len--) { c1 = tolower(*str1++); c2 = tolower(*str2++); if (c1 == 0 || c1 != c2) break; } return c1 - c2; } int aac_decode(aac_dec_opt *opt) { int result; int def_srate = 0; int outfile_set = 0; int mp4file = 0; char *fnp; char audioFileName[MAX_PATH]; unsigned char header[8]; FILE *hMP4File; /* point to the specified file name */ strcpy(audioFileName, opt->filename); fnp = (char *)strrchr(audioFileName,'.'); if (fnp) fnp[0] = '\0'; strcat(audioFileName, file_ext[opt->file_type]); mp4file = 0; hMP4File = fopen(opt->filename, "rb"); if (!hMP4File) { return 1; } fread(header, 1, 8, hMP4File); fclose(hMP4File); if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p') mp4file = 1; if (mp4file) { result = decodeMP4file(audioFileName, opt); } else { result = decodeAACfile(audioFileName, def_srate, opt); } return 0; }