From cea6d0c92f56cbd38ac8b480a9ea187d41bf55dd Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Mon, 31 Oct 2005 20:56:29 +0000 Subject: [PATCH] Initial check-in of AAC codec. Currently only recognises the .mp4 extension and is not yet capable of realtime operation git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7706 a1c6a512-1295-4272-9138-f99709370657 --- apps/FILES | 2 + apps/codecs/Makefile | 13 ++- apps/codecs/SOURCES | 1 + apps/codecs/aac.c | 184 +++++++++++++++++++++++++++++++++++++++++++ apps/metadata.c | 17 +++- apps/playback.c | 5 ++ apps/tree.c | 1 + tools/configure | 8 +- 8 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 apps/codecs/aac.c diff --git a/apps/FILES b/apps/FILES index 503f2e0abe..e89215da0c 100644 --- a/apps/FILES +++ b/apps/FILES @@ -35,6 +35,8 @@ codecs/SOURCES codecs/*.[ch] codecs/Makefile codecs/liba52/* +codecs/libfaad/* +codecs/libfaad/codebook/* codecs/libffmpegFLAC/* codecs/libmad/* codecs/libwavpack/* diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile index 3b86435208..b2afafc205 100644 --- a/apps/codecs/Makefile +++ b/apps/codecs/Makefile @@ -17,7 +17,7 @@ ifdef APPEXTRA endif ifdef SOFTWARECODECS - CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lm4a + CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a endif # we "borrow" the plugin LDS file @@ -39,7 +39,7 @@ DIRS = . CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a -.PHONY: libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libm4a +.PHONY: libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libfaad libm4a OUTPUT = $(SOFTWARECODECS) @@ -61,6 +61,7 @@ $(OBJDIR)/mpc.elf: $(OBJDIR)/mpc.o $(CODECDEPS) $(BUILDDIR)/libmusepack.a $(OBJDIR)/wav.elf: $(OBJDIR)/wav.o $(CODECDEPS) $(OBJDIR)/wavpack.elf: $(OBJDIR)/wavpack.o $(CODECDEPS) $(BUILDDIR)/libwavpack.a $(OBJDIR)/alac.elf: $(OBJDIR)/alac.o $(CODECDEPS) $(BUILDDIR)/libalac.a $(BUILDDIR)/libm4a.a +$(OBJDIR)/aac.elf: $(OBJDIR)/aac.o $(CODECDEPS) $(BUILDDIR)/libfaad.a $(BUILDDIR)/libm4a.a $(OBJDIR)/%.elf: $(OBJDIR)/%.o $(CODECDEPS) $(ELFIT) @@ -162,9 +163,14 @@ libm4a: @mkdir -p $(OBJDIR)/libm4a @$(MAKE) -C libm4a OBJDIR=$(OBJDIR)/libm4a OUTPUT=$(BUILDDIR)/libm4a.a +libfaad: + @echo "MAKE in libfaad" + @mkdir -p $(OBJDIR)/libfaad + @$(MAKE) -C libfaad OBJDIR=$(OBJDIR)/libfaad OUTPUT=$(BUILDDIR)/libfaad.a + clean: @echo "cleaning codecs" - $(SILENT)rm -fr $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(OBJDIR)/libffmpegFLAC $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/Tremor $(OBJDIR)/libwavpack $(OBJDIR)/dumb $(BUILDDIR)/libdumb.a $(BUILDDIR)/libdumbd.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a + $(SILENT)rm -fr $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(OBJDIR)/libffmpegFLAC $(OBJDIR)/Tremor $(OBJDIR)/libwavpack $(OBJDIR)/dumb $(BUILDDIR)/libdumb.a $(BUILDDIR)/libdumbd.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libfaad $(BUILDDIR)/libfaad.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a @$(MAKE) -C libmad clean OBJDIR=$(OBJDIR)/libmad @$(MAKE) -C liba52 clean OBJDIR=$(OBJDIR)/liba52 @$(MAKE) -C libffmpegFLAC clean OBJDIR=$(OBJDIR)/libffmpegFLAC @@ -172,6 +178,7 @@ clean: @$(MAKE) -C libwavpack clean OBJDIR=$(OBJDIR)/libwavpack @$(MAKE) -C libmusepack clean OBJDIR=$(OBJDIR)/libmusepack @$(MAKE) -C libalac clean OBJDIR=$(OBJDIR)/libalac + @$(MAKE) -C libfaad clean OBJDIR=$(OBJDIR)/libfaad @$(MAKE) -C libm4a clean OBJDIR=$(OBJDIR)/libm4a @$(MAKE) -C dumb clean OBJDIR=$(OBJDIR)/dumb @$(MAKE) -C lib clean OBJDIR=$(OBJDIR)/lib diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES index 14cf847d10..3ef2cd6af0 100644 --- a/apps/codecs/SOURCES +++ b/apps/codecs/SOURCES @@ -7,4 +7,5 @@ a52.c mpc.c wavpack.c alac.c +aac.c #endif diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c new file mode 100644 index 0000000000..79fb5cb262 --- /dev/null +++ b/apps/codecs/aac.c @@ -0,0 +1,184 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "codeclib.h" +#include "libm4a/m4a.h" +#include "libfaad/common.h" +#include "libfaad/structs.h" +#include "libfaad/decoder.h" + +#ifndef SIMULATOR +extern char iramcopy[]; +extern char iramstart[]; +extern char iramend[]; +#endif + +struct codec_api* rb; +struct codec_api* ci; + +/* this is the codec entry point */ +enum codec_status codec_start(struct codec_api* api) +{ + size_t n; + static demux_res_t demux_res; + stream_t input_stream; + uint32_t samplesdone; + uint32_t elapsedtime; + uint32_t sample_duration; + uint32_t sample_byte_size; + int samplesdecoded; + unsigned int i; + unsigned char* buffer; + static NeAACDecFrameInfo frameInfo; + NeAACDecHandle hDecoder; + int err; + int16_t* decodedbuffer; + + /* Generic codec initialisation */ + TEST_CODEC_API(api); + + rb = api; + ci = (struct codec_api*)api; + +#ifndef SIMULATOR + rb->memcpy(iramstart, iramcopy, iramend-iramstart); +#endif + + ci->configure(CODEC_SET_FILEBUF_LIMIT, (int *)(1024*1024*2)); + ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, (int *)(1024*16)); + ci->configure(CODEC_SET_FILEBUF_WATERMARK, (int *)(1024*512)); + + ci->configure(CODEC_DSP_ENABLE, (bool *)true); + ci->configure(DSP_DITHER, (bool *)false); + ci->configure(DSP_SET_STEREO_MODE, (int *)STEREO_INTERLEAVED); + ci->configure(DSP_SET_SAMPLE_DEPTH, (int *)(16)); + + next_track: + + if (codec_init(api)) { + LOGF("FAAD: Error initialising codec\n"); + return CODEC_ERROR; + } + + while (!rb->taginfo_ready) + rb->yield(); + + ci->configure(DSP_SET_FREQUENCY, (long *)(rb->id3->frequency)); + + stream_create(&input_stream,ci); + + /* if qtmovie_read returns successfully, the stream is up to + * the movie data, which can be used directly by the decoder */ + if (!qtmovie_read(&input_stream, &demux_res)) { + LOGF("FAAD: Error initialising file\n"); + return CODEC_ERROR; + } + + /* initialise the sound converter */ + hDecoder = NULL; + hDecoder = NeAACDecOpen(); + + if (!hDecoder) { + LOGF("FAAD: Error opening decoder\n"); + return CODEC_ERROR; + } + + NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(hDecoder); + conf->outputFormat = 1; // 16-bit integers + NeAACDecSetConfiguration(hDecoder, conf); + + unsigned long s=0; + unsigned char c=0; + + err = NeAACDecInit2(hDecoder, demux_res.codecdata,demux_res.codecdata_len, &s, &c); + if (err) { + LOGF("FAAD: Error initialising decoder: %d, type=%d\n", err,hDecoder->object_type); + return CODEC_ERROR; + } + + ci->id3->frequency=s; + + i=0; + samplesdone=0; + /* The main decoding loop */ + while (i < demux_res.num_sample_byte_sizes) { + rb->yield(); + if (ci->stop_codec || ci->reload_codec) { + break; + } + + /* Deal with any pending seek requests */ + if (ci->seek_time) { + if (alac_seek(&demux_res,&input_stream, + (ci->seek_time/10) * (ci->id3->frequency/100), + &samplesdone, &i)) { + elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); + ci->set_elapsed(elapsedtime); + } + ci->seek_time = 0; + } + + /* Lookup the length (in samples and bytes) of block i */ + if (!get_sample_info(&demux_res, i, &sample_duration, + &sample_byte_size)) { + LOGF("AAC: Error in get_sample_info\n"); + return CODEC_ERROR; + } + + /* Request the required number of bytes from the input buffer */ + buffer=ci->request_buffer((long*)&n,sample_byte_size); + + /* Decode one block - returned samples will be host-endian */ + rb->yield(); + decodedbuffer = NeAACDecDecode(hDecoder, &frameInfo, buffer, n); + + if (frameInfo.error > 0) { + LOGF("FAAD: decoding error \"%s\"\n", NeAACDecGetErrorMessage(frameInfo.error)); + return CODEC_ERROR; + } + + /* Get the number of decoded samples */ + samplesdecoded=frameInfo.samples; + + /* Advance codec buffer */ + ci->advance_buffer(n); + + /* Output the audio */ + rb->yield(); + while (!rb->pcmbuf_insert((char*)decodedbuffer, frameInfo.samples << 1)) + rb->yield(); + + /* Update the elapsed-time indicator */ + samplesdone+=sample_duration; + elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); + ci->set_elapsed(elapsedtime); + + /* Keep track of current position - for resuming */ + ci->set_offset(elapsedtime); + + i++; + } + + LOGF("AAC: Decoded %d samples\n",samplesdone); + + if (ci->request_next_track()) + goto next_track; + + return CODEC_OK; +} diff --git a/apps/metadata.c b/apps/metadata.c index f3fed96b84..a4fd6883d1 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -76,6 +76,7 @@ static const struct format_list formats[] = { AFMT_A52, "ac3" }, { AFMT_WAVPACK, "wv" }, { AFMT_ALAC, "m4a" }, + { AFMT_AAC, "mp4" }, }; static const unsigned short a52_bitrates[] = @@ -965,7 +966,7 @@ static bool get_wave_metadata(int fd, struct mp3entry* id3) -static bool get_alac_metadata(int fd, struct mp3entry* id3) +static bool get_m4a_metadata(int fd, struct mp3entry* id3) { unsigned char* buf; unsigned long totalsamples; @@ -1171,8 +1172,15 @@ static bool get_alac_metadata(int fd, struct mp3entry* id3) i+=4; /* Check the codec type - 'alac' for ALAC, 'mp4a' for AAC */ - if (memcmp(&buf[i],"alac",4)!=0) { - logf("Not an ALAC file\n"); + if ((id3->codectype==AFMT_ALAC) && + (memcmp(&buf[i],"alac",4)!=0)) { + logf("Not an ALAC file\n"); + return false; + } + + if ((id3->codectype==AFMT_AAC) && + (memcmp(&buf[i],"mp4a",4)!=0)) { + logf("Not a MP4 AAC file\n"); return false; } @@ -1425,7 +1433,8 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname, break; case AFMT_ALAC: - if (!get_alac_metadata(fd, &(track->id3))) + case AFMT_AAC: + if (!get_m4a_metadata(fd, &(track->id3))) { // return false; } diff --git a/apps/playback.c b/apps/playback.c index 16a54e98a0..37443df64f 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -75,6 +75,7 @@ static volatile bool paused; #define CODEC_MPC "/.rockbox/codecs/mpc.codec" #define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec" #define CODEC_ALAC "/.rockbox/codecs/alac.codec" +#define CODEC_AAC "/.rockbox/codecs/aac.codec" #define AUDIO_FILL_CYCLE (1024*256) #define AUDIO_DEFAULT_WATERMARK (1024*512) @@ -899,6 +900,10 @@ bool loadcodec(const char *trackname, bool start_play) logf("Codec: ALAC"); codec_path = CODEC_ALAC; break; + case AFMT_AAC: + logf("Codec: AAC"); + codec_path = CODEC_AAC; + break; default: logf("Codec: Unsupported"); snprintf(msgbuf, sizeof(msgbuf)-1, "No codec for: %s", trackname); diff --git a/apps/tree.c b/apps/tree.c index 4134c942d8..cd3d2717c7 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -90,6 +90,7 @@ const struct filetype filetypes[] = { { "mpc", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, { "wv", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, { "m4a", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, + { "mp4", TREE_ATTR_MPA, Icon_Audio, VOICE_EXT_MPA }, #endif { "m3u", TREE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, { "cfg", TREE_ATTR_CFG, Icon_Config, VOICE_EXT_CFG }, diff --git a/tools/configure b/tools/configure index 5f0310a83b..d15bdbc19a 100755 --- a/tools/configure +++ b/tools/configure @@ -523,7 +523,7 @@ appsdir='\$(ROOTDIR)/apps' archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libm4a" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libfaad libm4a" ;; 10) @@ -537,7 +537,7 @@ appsdir='\$(ROOTDIR)/apps' archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libm4a" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libfaad libm4a" ;; 11) @@ -551,7 +551,7 @@ appsdir='\$(ROOTDIR)/apps' archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libm4a" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libfaad libm4a" ;; 12) @@ -565,7 +565,7 @@ appsdir='\$(ROOTDIR)/apps' archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libm4a" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack dumb libmusepack libalac libfaad libm4a" ;; *)