From cc2160de5cc05dc3aa77f3a34358e66f6193c8c9 Mon Sep 17 00:00:00 2001 From: Michał Cichoń Date: Tue, 26 Jun 2012 20:35:30 +0200 Subject: Add support for AAC. --- faad2/src/frontend/Makefile.am | 12 + faad2/src/frontend/audio.c | 500 ++++++++++++++++ faad2/src/frontend/audio.h | 75 +++ faad2/src/frontend/faad.man | 85 +++ faad2/src/frontend/faad.sln | 36 ++ faad2/src/frontend/faad.vcproj | 256 ++++++++ faad2/src/frontend/main.c | 1270 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2234 insertions(+) create mode 100644 faad2/src/frontend/Makefile.am create mode 100644 faad2/src/frontend/audio.c create mode 100644 faad2/src/frontend/audio.h create mode 100644 faad2/src/frontend/faad.man create mode 100644 faad2/src/frontend/faad.sln create mode 100644 faad2/src/frontend/faad.vcproj create mode 100644 faad2/src/frontend/main.c (limited to 'faad2/src/frontend') diff --git a/faad2/src/frontend/Makefile.am b/faad2/src/frontend/Makefile.am new file mode 100644 index 0000000..8bda787 --- /dev/null +++ b/faad2/src/frontend/Makefile.am @@ -0,0 +1,12 @@ +bin_PROGRAMS = faad +man_MANS = faad.man + +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/common/faad \ + -I$(top_srcdir)/common/mp4ff + +faad_LDADD = $(top_builddir)/libfaad/libfaad.la \ + $(top_builddir)/common/mp4ff/libmp4ff.a + +faad_SOURCES = main.c \ + audio.c audio.h \ + $(top_srcdir)/common/faad/getopt.c diff --git a/faad2/src/frontend/audio.c b/faad2/src/frontend/audio.c new file mode 100644 index 0000000..7691ce9 --- /dev/null +++ b/faad2/src/frontend/audio.c @@ -0,0 +1,500 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: audio.c,v 1.29 2008/09/19 22:50:17 menno Exp $ +**/ + +#ifdef _WIN32 +#include +#endif +#include +#include +#include +#include +#include +#include "audio.h" + + +audio_file *open_audio_file(char *infile, int samplerate, int channels, + int outputFormat, int fileType, long channelMask) +{ + audio_file *aufile = 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"); + } + + 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 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 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); +} + +static int 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); +} + +static int 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); +} + +static int 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 = 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; +} + +static int 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 = 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; +} + +static int 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 = 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; +} + +static int 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 = 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; +} diff --git a/faad2/src/frontend/audio.h b/faad2/src/frontend/audio.h new file mode 100644 index 0000000..b4d3a67 --- /dev/null +++ b/faad2/src/frontend/audio.h @@ -0,0 +1,75 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: audio.h,v 1.19 2007/11/01 12:33:29 menno Exp $ +**/ + +#ifndef AUDIO_H_INCLUDED +#define AUDIO_H_INCLUDED + +#ifdef __cplusplus +extern "C" { +#endif + +#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; + +audio_file *open_audio_file(char *infile, int samplerate, int channels, + int outputFormat, int fileType, long channelMask); +int write_audio_file(audio_file *aufile, void *sample_buffer, int samples, int offset); +void close_audio_file(audio_file *aufile); +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); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/faad2/src/frontend/faad.man b/faad2/src/frontend/faad.man new file mode 100644 index 0000000..83727c7 --- /dev/null +++ b/faad2/src/frontend/faad.man @@ -0,0 +1,85 @@ +.TH FAAD "1" "October 2006" "faad 2.5" "" +.SH NAME +faad \(em Process an Advanced Audio Codec stream + +.SH "SYNOPSIS" +.B faad +[options] [\-w | \-o | \-a ] input_filename + +.SH "DESCRIPTION" +This utility provides a command line interface to libfaad2. This program reads in MPEG\(hy4 AAC files, processes, and outputs them in either Microsoft WAV, MPEG\(hy4 AAC ADTS, or standard PCM formats. + +.SH "OPTIONS" +.TP +.BI \-a " " ", \-\^\-adtsout" " " +Sets the processing to output to the specified file in MPEG\(hy4 AAC ADTS format +.TP +.BI \-b " " ", \-\^\-bits" " " +Set the output (individual) sample format. The number takes one of the following values: +.RS +.RS +1: 16\(hybit PCM data (default). +.br +2: 24\(hybit PCM data. +.br +3: 32\(hybit PCM data. +.br +4: 32\(hybit floating\hy(point data. +.br +5: 64\(hybit floating\hy(point data. +.RE +.RE +.TP +.B \-d ", \-\^\-downmix" +Set the processing to downsample from 5.1 (surround sound and bass) channels to 2 channels (stereo). +.TP +.BI \-f " " ", \-\^\-format" " " +Set the output file format. The number takes one of the following values: +.RS +.RS +1: Microsoft WAV format (default). +.br +2: Raw PCM data. +.RE +.RE +.TP +.BI \-g +Set the processing to not perform gapless decoding. +.TP +.B \-h ", \-\^\-help" +Shows a usage summary. +.TP +.B \-i ", \-\^\-info" +Shows information about the about the input file. +.TP +.BI \-l " " ", \-\^\-objecttype" " " +Sets the MPEG\hy(4 profile and object type for the processing to use. The number takes one of the following values: +.RS +.RS +1: Main object type. +.br +2: Low Complexity (LC) object type (default). +.br +4: Long Term Prediction (LTP) object type. +.br +23: Low Delay (LD) object type. +.RE +.RE +.TP +.BI \-o " " ", \-\^\-outfile" " " +Sets the filename for processing output. +.TP +.B \-q ", \-\^\-quiet" +Quiet \- Suppresses status messages during processing. +.TP +.B \-t ", \-\^\-oldformat" +Sets the processing to use the old MPEG\(hy4 AAC ADTS format when outputting in said format. +.TP +.B \-w ", \-\^\-stdio" +Sets the processing output to be sent to the standard out. + +.SH "AUTHOR" +Matthew W. S. Bell + +.SH "SEE ALSO" +\fBfaac\fP(1) \ No newline at end of file diff --git a/faad2/src/frontend/faad.sln b/faad2/src/frontend/faad.sln new file mode 100644 index 0000000..f8f1596 --- /dev/null +++ b/faad2/src/frontend/faad.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "faad", "faad.vcproj", "{2BD8CBB3-DFC9-4A6A-9B7A-07ED749BED58}" + ProjectSection(ProjectDependencies) = postProject + {F470BB4A-7675-4D6A-B310-41F33AC6F987} = {F470BB4A-7675-4D6A-B310-41F33AC6F987} + {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114} = {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfaad", "..\libfaad\libfaad.vcproj", "{BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mp4ff", "..\common\mp4ff\mp4ff.vcproj", "{F470BB4A-7675-4D6A-B310-41F33AC6F987}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2BD8CBB3-DFC9-4A6A-9B7A-07ED749BED58}.Debug|Win32.ActiveCfg = Debug|Win32 + {2BD8CBB3-DFC9-4A6A-9B7A-07ED749BED58}.Debug|Win32.Build.0 = Debug|Win32 + {2BD8CBB3-DFC9-4A6A-9B7A-07ED749BED58}.Release|Win32.ActiveCfg = Release|Win32 + {2BD8CBB3-DFC9-4A6A-9B7A-07ED749BED58}.Release|Win32.Build.0 = Release|Win32 + {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Debug|Win32.ActiveCfg = Debug|Win32 + {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Debug|Win32.Build.0 = Debug|Win32 + {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Release|Win32.ActiveCfg = Release|Win32 + {BC3EFE27-9015-4C9C-AD3C-72B3B7ED2114}.Release|Win32.Build.0 = Release|Win32 + {F470BB4A-7675-4D6A-B310-41F33AC6F987}.Debug|Win32.ActiveCfg = Debug|Win32 + {F470BB4A-7675-4D6A-B310-41F33AC6F987}.Debug|Win32.Build.0 = Debug|Win32 + {F470BB4A-7675-4D6A-B310-41F33AC6F987}.Release|Win32.ActiveCfg = Release|Win32 + {F470BB4A-7675-4D6A-B310-41F33AC6F987}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/faad2/src/frontend/faad.vcproj b/faad2/src/frontend/faad.vcproj new file mode 100644 index 0000000..b33f6f4 --- /dev/null +++ b/faad2/src/frontend/faad.vcproj @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/faad2/src/frontend/main.c b/faad2/src/frontend/main.c new file mode 100644 index 0000000..2f97c07 --- /dev/null +++ b/faad2/src/frontend/main.c @@ -0,0 +1,1270 @@ +/* +** FAAD2 - Freeware Advanced Audio (AAC) Decoder including SBR decoding +** Copyright (C) 2003-2005 M. Bakker, Nero AG, http://www.nero.com +** +** 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. +** +** Any non-GPL usage of this software or parts of this software is strictly +** forbidden. +** +** The "appropriate copyright message" mentioned in section 2c of the GPLv2 +** must read: "Code from FAAD2 is copyright (c) Nero AG, www.nero.com" +** +** Commercial non-GPL licensing of this software is possible. +** For more info contact Nero AG through Mpeg4AAClicense@nero.com. +** +** $Id: main.c,v 1.85 2008/09/22 17:55:09 menno Exp $ +**/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define off_t __int64 +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "audio.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 */ + + +static int quiet = 0; + +static void faad_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + + if (!quiet) + { + va_start(ap, fmt); + + vfprintf(stream, fmt, ap); + + va_end(ap); + } +} + +/* 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; + + +static int 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; +} + +static void 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; +} + +static int adts_sample_rates[] = {96000,88200,64000,48000,44100,32000,24000,22050,16000,12000,11025,8000,7350,0,0,0}; + +static int 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; +} + + + +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); +} + +/* 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 + +static 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; + } +} + +static char *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 ""; +} + +static void print_channel_info(NeAACDecFrameInfo *frameInfo) +{ + /* print some 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"); +} + +static int FindAdtsSRIndex(int sr) +{ + int i; + + for (i = 0; i < 16; i++) + { + if (sr == adts_sample_rates[i]) + return i; + } + return 16 - 1; +} + +static unsigned char *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 = 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; +} + +/* globals */ +char *progName; + +static const char *file_ext[] = +{ + NULL, + ".wav", + ".aif", + ".au", + ".au", + ".pcm", + NULL +}; + +static void usage(void) +{ + faad_fprintf(stdout, "\nUsage:\n"); + faad_fprintf(stdout, "%s [options] infile.aac\n", progName); + faad_fprintf(stdout, "Options:\n"); + faad_fprintf(stdout, " -h Shows this help screen.\n"); + faad_fprintf(stdout, " -i Shows info about the input file.\n"); + faad_fprintf(stdout, " -a X Write MPEG-4 AAC ADTS output file.\n"); + faad_fprintf(stdout, " -t Assume old ADTS format.\n"); + faad_fprintf(stdout, " -o X Set output filename.\n"); + faad_fprintf(stdout, " -f X Set output format. Valid values for X are:\n"); + faad_fprintf(stdout, " 1: Microsoft WAV format (default).\n"); + faad_fprintf(stdout, " 2: RAW PCM data.\n"); + faad_fprintf(stdout, " -b X Set output sample format. Valid values for X are:\n"); + faad_fprintf(stdout, " 1: 16 bit PCM data (default).\n"); + faad_fprintf(stdout, " 2: 24 bit PCM data.\n"); + faad_fprintf(stdout, " 3: 32 bit PCM data.\n"); + faad_fprintf(stdout, " 4: 32 bit floating point data.\n"); + faad_fprintf(stdout, " 5: 64 bit floating point data.\n"); + faad_fprintf(stdout, " -s X Force the samplerate to X (for RAW files).\n"); + faad_fprintf(stdout, " -l X Set object type. Supported object types:\n"); + faad_fprintf(stdout, " 1: Main object type.\n"); + faad_fprintf(stdout, " 2: LC (Low Complexity) object type.\n"); + faad_fprintf(stdout, " 4: LTP (Long Term Prediction) object type.\n"); + faad_fprintf(stdout, " 23: LD (Low Delay) object type.\n"); + faad_fprintf(stdout, " -d Down matrix 5.1 to 2 channels\n"); + faad_fprintf(stdout, " -w Write output to stdio instead of a file.\n"); + faad_fprintf(stdout, " -g Disable gapless decoding.\n"); + faad_fprintf(stdout, " -q Quiet - suppresses status messages.\n"); + faad_fprintf(stdout, "Example:\n"); + faad_fprintf(stdout, " %s infile.aac\n", progName); + faad_fprintf(stdout, " %s infile.mp4\n", progName); + faad_fprintf(stdout, " %s -o outfile.wav infile.aac\n", progName); + faad_fprintf(stdout, " %s -w infile.aac > outfile.wav\n", progName); + faad_fprintf(stdout, " %s -a outfile.aac infile.aac\n", progName); + return; +} + +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) +{ + int tagsize; + unsigned long samplerate; + unsigned char channels; + void *sample_buffer; + + audio_file *aufile; + + FILE *adtsFile; + 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"); + if (adtsFile == NULL) + { + faad_fprintf(stderr, "Error opening file: %s\n", adts_fn); + return 1; + } + } + + b.infile = fopen(aacfile, "rb"); + if (b.infile == NULL) + { + /* unable to open file */ + 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(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(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(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 = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels, + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + } else { + aufile = 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(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(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 (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) + close_audio_file(aufile); + + if (b.buffer) + free(b.buffer); + + return frameInfo.error; +} + +static 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; +} + +static const unsigned long srates[] = +{ + 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, + 12000, 11025, 8000 +}; + +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) +{ + int track; + unsigned long samplerate; + unsigned char channels; + void *sample_buffer; + + mp4ff_t *infile; + long sampleId, numSamples; + + audio_file *aufile; + + FILE *mp4File; + FILE *adtsFile; + unsigned char *adtsData; + int adtsDataSize; + + NeAACDecHandle hDecoder; + NeAACDecConfigurationPtr config; + NeAACDecFrameInfo frameInfo; + mp4AudioSpecificConfig mp4ASC; + + unsigned char *buffer; + int buffer_size; + + char percents[200]; + int percent, old_percent = -1; + + int first_time = 1; + + /* for gapless decoding */ + unsigned int useAacLength = 1; + unsigned int initial = 1; + unsigned int framesize; + unsigned long timescale; + + + /* initialise the callback structure */ + mp4ff_callback_t *mp4cb = malloc(sizeof(mp4ff_callback_t)); + + mp4File = fopen(mp4file, "rb"); + mp4cb->read = read_callback; + mp4cb->seek = seek_callback; + mp4cb->user_data = mp4File; + + + hDecoder = NeAACDecOpen(); + + /* Set configuration */ + config = NeAACDecGetCurrentConfiguration(hDecoder); + config->outputFormat = outputFormat; + config->downMatrix = downMatrix; + //config->dontUpSampleImplicitSBR = 1; + NeAACDecSetConfiguration(hDecoder, config); + + if (adts_out) + { + adtsFile = fopen(adts_fn, "wb"); + if (adtsFile == NULL) + { + faad_fprintf(stderr, "Error opening file: %s\n", adts_fn); + return 1; + } + } + + infile = mp4ff_open_read(mp4cb); + if (!infile) + { + /* unable to open file */ + faad_fprintf(stderr, "Error opening file: %s\n", mp4file); + return 1; + } + + if ((track = GetAACTrack(infile)) < 0) + { + faad_fprintf(stderr, "Unable to find correct AAC sound track in the MP4 file.\n"); + NeAACDecClose(hDecoder); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 1; + } + + buffer = NULL; + buffer_size = 0; + mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); + + if(NeAACDecInit2(hDecoder, buffer, buffer_size, + &samplerate, &channels) < 0) + { + /* If some error initializing occured, skip the file */ + faad_fprintf(stderr, "Error initializing decoder library.\n"); + NeAACDecClose(hDecoder); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 1; + } + + timescale = mp4ff_time_scale(infile, track); + framesize = 1024; + useAacLength = 0; + + if (buffer) + { + if (NeAACDecAudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0) + { + if (mp4ASC.frameLengthFlag == 1) framesize = 960; + if (mp4ASC.sbr_present_flag == 1) framesize *= 2; + } + free(buffer); + } + + /* print some mp4 file info */ + faad_fprintf(stderr, "%s file info:\n\n", mp4file); + { + char *tag = NULL, *item = NULL; + int k, j; + char *ot[6] = { "NULL", "MAIN AAC", "LC AAC", "SSR AAC", "LTP AAC", "HE AAC" }; + long samples = mp4ff_num_samples(infile, track); + float f = 1024.0; + float seconds; + if (mp4ASC.sbr_present_flag == 1) + { + f = f * 2.0; + } + seconds = (float)samples*(float)(f-1.0)/(float)mp4ASC.samplingFrequency; + + *song_length = seconds; + + faad_fprintf(stderr, "%s\t%.3f secs, %d ch, %d Hz\n\n", ot[(mp4ASC.objectTypeIndex > 5)?0:mp4ASC.objectTypeIndex], + seconds, mp4ASC.channelsConfiguration, mp4ASC.samplingFrequency); + +#define PRINT_MP4_METADATA +#ifdef PRINT_MP4_METADATA + j = mp4ff_meta_get_num_items(infile); + for (k = 0; k < j; k++) + { + if (mp4ff_meta_get_by_index(infile, k, &item, &tag)) + { + if (item != NULL && tag != NULL) + { + faad_fprintf(stderr, "%s: %s\n", item, tag); + free(item); item = NULL; + free(tag); tag = NULL; + } + } + } + if (j > 0) faad_fprintf(stderr, "\n"); +#endif + } + + if (infoOnly) + { + NeAACDecClose(hDecoder); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 0; + } + + numSamples = mp4ff_num_samples(infile, track); + + for (sampleId = 0; sampleId < numSamples; sampleId++) + { + int rc; + long dur; + unsigned int sample_count; + unsigned int delay = 0; + + /* get acces unit from MP4 file */ + buffer = NULL; + buffer_size = 0; + + dur = mp4ff_get_sample_duration(infile, track, sampleId); + rc = mp4ff_read_sample(infile, track, sampleId, &buffer, &buffer_size); + if (rc == 0) + { + faad_fprintf(stderr, "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 (adts_out == 1) + { + adtsData = MakeAdtsHeader(&adtsDataSize, &frameInfo, 0); + + /* write the adts header */ + fwrite(adtsData, 1, adtsDataSize, adtsFile); + + fwrite(buffer, 1, frameInfo.bytesconsumed, adtsFile); + } + + if (buffer) free(buffer); + + if (!noGapless) + { + if (sampleId == 0) dur = 0; + + if (useAacLength || (timescale != samplerate)) { + sample_count = frameInfo.samples; + } else { + sample_count = (unsigned int)(dur * frameInfo.channels); + if (sample_count > frameInfo.samples) + sample_count = frameInfo.samples; + + if (!useAacLength && !initial && (sampleId < numSamples/2) && (sample_count != frameInfo.samples)) + { + faad_fprintf(stderr, "MP4 seems to have incorrect frame duration, using values from AAC data.\n"); + useAacLength = 1; + sample_count = frameInfo.samples; + } + } + + if (initial && (sample_count < framesize*frameInfo.channels) && (frameInfo.samples > sample_count)) + delay = frameInfo.samples - sample_count; + } else { + sample_count = frameInfo.samples; + } + + /* 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 = open_audio_file(sndfile, frameInfo.samplerate, frameInfo.channels, + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + } else { +#ifdef _WIN32 + setmode(fileno(stdout), O_BINARY); +#endif + aufile = open_audio_file("-", frameInfo.samplerate, frameInfo.channels, + outputFormat, fileType, aacChannelConfig2wavexChannelMask(&frameInfo)); + } + if (aufile == NULL) + { + NeAACDecClose(hDecoder); + mp4ff_close(infile); + free(mp4cb); + fclose(mp4File); + return 0; + } + } + first_time = 0; + } + + if (sample_count > 0) initial = 0; + + percent = min((int)(sampleId*100)/numSamples, 100); + if (percent > old_percent) + { + old_percent = percent; + sprintf(percents, "%d%% decoding %s.", percent, mp4file); + faad_fprintf(stderr, "%s\r", percents); +#ifdef _WIN32 + SetConsoleTitle(percents); +#endif + } + + if ((frameInfo.error == 0) && (sample_count > 0) && (!adts_out)) + { + if (write_audio_file(aufile, sample_buffer, sample_count, delay) == 0) + break; + } + + if (frameInfo.error > 0) + { + faad_fprintf(stderr, "Warning: %s\n", + NeAACDecGetErrorMessage(frameInfo.error)); + } + } + + NeAACDecClose(hDecoder); + + if (adts_out == 1) + { + fclose(adtsFile); + } + + mp4ff_close(infile); + + if (!first_time && !adts_out) + close_audio_file(aufile); + + free(mp4cb); + fclose(mp4File); + + return frameInfo.error; +} + +int main(int argc, char *argv[]) +{ + int result; + int infoOnly = 0; + int writeToStdio = 0; + int object_type = LC; + int def_srate = 0; + int downMatrix = 0; + int format = 1; + int outputFormat = FAAD_FMT_16BIT; + int outfile_set = 0; + int adts_out = 0; + int old_format = 0; + int showHelp = 0; + int mp4file = 0; + int noGapless = 0; + char *fnp; + char aacFileName[255]; + char audioFileName[255]; + char adtsFileName[255]; + unsigned char header[8]; + float length = 0; + FILE *hMP4File; + +/* System dependant types */ +#ifdef _WIN32 + long begin; +#else + clock_t begin; +#endif + + unsigned long cap = NeAACDecGetCapabilities(); + + + /* begin process command line */ + progName = argv[0]; + while (1) { + int c = -1; + int option_index = 0; + static struct option long_options[] = { + { "quiet", 0, 0, 'q' }, + { "outfile", 0, 0, 'o' }, + { "adtsout", 0, 0, 'a' }, + { "oldformat", 0, 0, 't' }, + { "format", 0, 0, 'f' }, + { "bits", 0, 0, 'b' }, + { "samplerate", 0, 0, 's' }, + { "objecttype", 0, 0, 'l' }, + { "downmix", 0, 0, 'd' }, + { "info", 0, 0, 'i' }, + { "stdio", 0, 0, 'w' }, + { "stdio", 0, 0, 'g' }, + { "help", 0, 0, 'h' }, + { 0, 0, 0, 0 } + }; + + c = getopt_long(argc, argv, "o:a:s:f:b:l:wgdhitq", + long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 'o': + if (optarg) + { + outfile_set = 1; + strcpy(audioFileName, optarg); + } + break; + case 'a': + if (optarg) + { + adts_out = 1; + strcpy(adtsFileName, optarg); + } + break; + case 's': + if (optarg) + { + char dr[10]; + if (sscanf(optarg, "%s", dr) < 1) { + def_srate = 0; + } else { + 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 > 2)) + 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 > 5)) + showHelp = 1; + } + } + break; + case 'l': + if (optarg) + { + char dr[10]; + if (sscanf(optarg, "%s", dr) < 1) + { + object_type = LC; /* default */ + } else { + object_type = atoi(dr); + if ((object_type != LC) && + (object_type != MAIN) && + (object_type != LTP) && + (object_type != LD)) + { + showHelp = 1; + } + } + } + break; + case 't': + old_format = 1; + break; + case 'd': + downMatrix = 1; + break; + case 'w': + writeToStdio = 1; + break; + case 'g': + noGapless = 1; + break; + case 'i': + infoOnly = 1; + break; + case 'h': + showHelp = 1; + break; + case 'q': + quiet = 1; + break; + default: + break; + } + } + + + faad_fprintf(stderr, " *********** Ahead Software MPEG-4 AAC Decoder V%s ******************\n\n", FAAD2_VERSION); + faad_fprintf(stderr, " Build: %s\n", __DATE__); + faad_fprintf(stderr, " Copyright 2002-2004: Ahead Software AG\n"); + faad_fprintf(stderr, " http://www.audiocoding.com\n"); + if (cap & FIXED_POINT_CAP) + faad_fprintf(stderr, " Fixed point version\n"); + else + faad_fprintf(stderr, " Floating point version\n"); + faad_fprintf(stderr, "\n"); + faad_fprintf(stderr, " This program is free software; you can redistribute it and/or modify\n"); + faad_fprintf(stderr, " it under the terms of the GNU General Public License.\n"); + faad_fprintf(stderr, "\n"); + faad_fprintf(stderr, " **************************************************************************\n\n"); + + + /* check that we have at least two non-option arguments */ + /* Print help if requested */ + if (((argc - optind) < 1) || showHelp) + { + usage(); + return 1; + } + +#if 0 + /* only allow raw data on stdio */ + if (writeToStdio == 1) + { + format = 2; + } +#endif + + /* point to the specified file name */ + strcpy(aacFileName, argv[optind]); + +#ifdef _WIN32 + begin = GetTickCount(); +#else + begin = clock(); +#endif + + /* 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]); + } + + /* check for mp4 file */ + mp4file = 0; + hMP4File = fopen(aacFileName, "rb"); + if (!hMP4File) + { + faad_fprintf(stderr, "Error opening file: %s\n", aacFileName); + 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(aacFileName, audioFileName, adtsFileName, writeToStdio, + outputFormat, format, downMatrix, noGapless, infoOnly, adts_out, &length); + } else { + result = decodeAACfile(aacFileName, audioFileName, adtsFileName, writeToStdio, + def_srate, object_type, outputFormat, format, downMatrix, infoOnly, adts_out, + old_format, &length); + } + + if (!result && !infoOnly) + { +#ifdef _WIN32 + float dec_length = (float)(GetTickCount()-begin)/1000.0; + 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). + */ + float dec_length = (float)(clock() - begin)/(float)CLOCKS_PER_SEC; +#endif + faad_fprintf(stderr, "Decoding %s took: %5.2f sec. %5.2fx real-time.\n", aacFileName, + dec_length, length/dec_length); + } + + return 0; +} -- cgit v1.2.3