From 4c1eb9225d5a741e1234d48eb38a8df3da908259 Mon Sep 17 00:00:00 2001
From: Warren Dukes <warren.dukes@gmail.com>
Date: Sun, 21 Mar 2004 21:32:23 +0000
Subject: [PATCH] add aac_decode.[ch] and start working on it also, if locale
 is C or POSIX, set fs charset to iso-8859-1

git-svn-id: https://svn.musicpd.org/mpd/trunk@347 09075e82-0dd4-0310-85a5-a0d7c8717e4f
---
 src/Makefile.am  |   4 +-
 src/aac_decode.c | 460 +++++++++++++++++++++++++++++++++++++++++++++++
 src/aac_decode.h |  36 ++++
 src/directory.c  |  12 +-
 src/main.c       |  12 +-
 src/mp4_decode.h |   2 +-
 src/path.c       |  42 +++--
 src/tag.c        | 170 +-----------------
 8 files changed, 545 insertions(+), 193 deletions(-)
 create mode 100644 src/aac_decode.c
 create mode 100644 src/aac_decode.h

diff --git a/src/Makefile.am b/src/Makefile.am
index 7e4b12090..16f74d57f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -5,13 +5,13 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
 	tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \
 	audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \
 	audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \
-	mp4_decode.h
+	mp4_decode.h aac_decode.h
 mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
 	song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \
 	tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \
 	audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
 	audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \
-	$(mpd_headers)
+	aac_decode.c $(mpd_headers)
 
 mpd_CFLAGS = $(MPD_CFLAGS)
 mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
diff --git a/src/aac_decode.c b/src/aac_decode.c
new file mode 100644
index 000000000..26e430d06
--- /dev/null
+++ b/src/aac_decode.c
@@ -0,0 +1,460 @@
+/* the Music Player Daemon (MPD)
+ * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
+ * This project's homepage is: http://www.musicpd.org
+ * 
+ * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
+ * 
+ * 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
+ */
+
+#include "aac_decode.h"
+
+#ifdef HAVE_FAAD
+
+#define AAC_MAX_CHANNELS	6
+
+#include "command.h"
+#include "utils.h"
+#include "audio.h"
+#include "log.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <faad.h>
+
+/* all code here is either based on or copied from FAAD2's frontend code */
+typedef struct {
+	long bytesIntoBuffer;
+	long bytesConsumed;
+	long fileOffset;
+	unsigned char *buffer;
+	int atEof;
+	FILE *infile;
+} AacBuffer;
+
+void fillAacBuffer(AacBuffer *b) {
+	if(b->bytesConsumed > 0) {
+		int bread;
+
+		if(b->bytesIntoBuffer) {
+			memmove((void *)b->buffer,(void*)(b->buffer+
+					b->bytesConsumed),b->bytesIntoBuffer);
+		}
+
+		if(!b->atEof) {
+			bread = fread((void *)(b->buffer+b->bytesIntoBuffer),1,
+					b->bytesConsumed,b->infile);
+			if(bread!=b->bytesConsumed) b->atEof = 1;
+			b->bytesIntoBuffer+=bread;
+		}
+
+		b->bytesConsumed = 0;
+
+		if(b->bytesIntoBuffer > 3) {
+			if(memcmp(b->buffer,"TAG",3)==0) b->bytesIntoBuffer = 0;
+		}
+		if(b->bytesIntoBuffer > 11) {
+			if(memcmp(b->buffer,"LYRICSBEGIN",11)==0) {
+				b->bytesIntoBuffer = 0;
+			}
+		}
+		if(b->bytesIntoBuffer > 8) {
+			if(memcmp(b->buffer,"APETAGEX",8)==0) {
+				b->bytesIntoBuffer = 0;
+			}
+		}
+	}
+}
+
+void advanceAacBuffer(AacBuffer * b, int bytes) {
+	b->fileOffset+=bytes;
+	b->bytesConsumed = bytes;
+	b->bytesIntoBuffer-=bytes;
+}
+
+static int adtsSampleRates[] = {96000,88200,64000,48000,44100,32000,24000,22050,
+				16000,12000,11025,8000,7350,0,0,0};
+
+int adtsParse(AacBuffer * b, float * length) {
+	int frames, frameLength;
+	int tFrameLength = 0;
+	int sampleRate = 0;
+	float framesPerSec, bytesPerFrame;
+
+	/* Read all frames to ensure correct time and bitrate */
+	for(frames = 0; ;frames++) {
+		fillAacBuffer(b);
+
+		if(b->bytesIntoBuffer > 7) {
+			/* check syncword */
+			if (!((b->buffer[0] == 0xFF) && 
+				((b->buffer[1] & 0xF6) == 0xF0)))
+			{
+				break;
+			}
+
+			if(frames==0) {
+				sampleRate = adtsSampleRates[
+						(b->buffer[2]&0x3c)>>2];
+			}
+
+			frameLength =  ((((unsigned int)b->buffer[3] & 0x3)) 
+					<< 11) | (((unsigned int)b->buffer[4])  
+                			<< 3) | (b->buffer[5] >> 5);
+
+			tFrameLength+=frameLength;
+
+			if(frameLength > b->bytesIntoBuffer) break;
+
+			advanceAacBuffer(b,frameLength);
+		}
+		else break;
+	}
+
+	framesPerSec = (float)sampleRate/1024.0;
+	if(frames!=0) {
+		bytesPerFrame = (float)tFrameLength/(float)(frames*1000);
+	}
+	else bytesPerFrame = 0;
+	if(framesPerSec!=0) *length = (float)frames/framesPerSec;
+
+	return 1;
+}
+
+int initAacBuffer(char * file, AacBuffer * b, float * length) {
+	size_t fileread;
+	size_t bread;
+	size_t tagsize;
+
+	*length = -1;
+
+	memset(b,0,sizeof(AacBuffer));
+
+	b->infile = fopen(file,"r");
+	if(b->infile == NULL) return -1;
+
+	fseek(b->infile,0,SEEK_END);
+	fileread = ftell(b->infile);
+	fseek(b->infile,0,SEEK_SET);
+
+	b->buffer = malloc(FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
+	memset(b->buffer,0,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
+
+	bread = fread(b->buffer,1,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
+			b->infile);
+	b->bytesIntoBuffer = bread;
+	b->bytesConsumed = 0;
+	b->fileOffset = 0;
+
+	if(bread!=FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
+
+	tagsize = 0;
+	if(!memcmp(b->buffer,"ID3",3)) {
+		tagsize = (b->buffer[6] << 21) | (b->buffer[7] << 14) |
+				(b->buffer[8] << 7) | (b->buffer[9] << 0);
+
+		tagsize+=10;
+		advanceAacBuffer(b,tagsize);
+		fillAacBuffer(b);
+	}
+
+	if((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
+		adtsParse(b, length);
+		fseek(b->infile, tagsize, SEEK_SET);
+
+		bread = fread(b->buffer, 1, 
+				FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
+				b->infile);
+		if(bread != FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
+		else b->atEof = 0;
+		b->bytesIntoBuffer = bread;
+		b->bytesConsumed = 0;
+		b->fileOffset = tagsize;
+	}
+	else if(memcmp(b->buffer,"ADIF",4) == 0) {
+		int bitRate;
+		int skipSize = (b->buffer[4] & 0x80) ? 9 : 0;
+		bitRate = ((unsigned int)(b->buffer[4 + skipSize] & 0x0F)<<19) |
+            			((unsigned int)b->buffer[5 + skipSize]<<11) |
+            			((unsigned int)b->buffer[6 + skipSize]<<3) |
+            			((unsigned int)b->buffer[7 + skipSize] & 0xE0);
+
+		*length = fileread;
+		if(*length!=0 && bitRate!=0) *length = *length*8.0/bitRate;
+	}
+
+	if(*length<0) return -1;
+
+	return 0;
+}
+
+int getAacTotalTime(char * file) {
+	AacBuffer b;
+	float length;
+
+	if(initAacBuffer(file,&b,&length) < 0) return -1;
+
+	if(b.buffer) free(b.buffer);
+	fclose(b.infile);
+
+	return (int)(length+0.5);
+}
+
+
+int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
+	/*FILE * fh;
+	mp4ff_t * mp4fh;
+	mp4ff_callback_t * mp4cb; 
+	int32_t track;
+	float time;
+	int32_t scale;
+	faacDecHandle decoder;
+	faacDecFrameInfo frameInfo;
+	faacDecConfigurationPtr config;
+	unsigned char * mp4Buffer;
+	int mp4BufferSize;
+	unsigned long sampleRate;
+	unsigned char channels;
+	long sampleId;
+	long numSamples;
+	int eof = 0;
+	long dur;
+	unsigned int sampleCount;
+	char * sampleBuffer;
+	size_t sampleBufferLen;
+	unsigned int initial = 1;
+	int chunkLen = 0;
+	float * seekTable;
+	long seekTableEnd = -1;
+	int seekPositionFound = 0;
+	long offset;
+	mpd_uint16 bitRate = 0;
+
+	fh = fopen(dc->file,"r");
+	if(!fh) {
+		ERROR("failed to open %s\n",dc->file);
+		return -1;
+	}
+
+	mp4cb = malloc(sizeof(mp4ff_callback_t));
+	mp4cb->read = mp4_readCallback;
+	mp4cb->seek = mp4_seekCallback;
+	mp4cb->user_data = fh;
+
+	mp4fh = mp4ff_open_read(mp4cb);
+	if(!mp4fh) {
+		ERROR("Input does not appear to be a mp4 stream.\n");
+		free(mp4cb);
+		fclose(fh);
+		return -1;
+	}
+
+	track = mp4_getAACTrack(mp4fh);
+	if(track < 0) {
+		ERROR("No AAC track found in mp4 stream.\n");
+		mp4ff_close(mp4fh);
+		fclose(fh);
+		free(mp4cb);
+		return -1;
+	}
+
+	decoder = faacDecOpen();
+
+	config = faacDecGetCurrentConfiguration(decoder);
+	config->outputFormat = FAAD_FMT_16BIT;
+#ifdef HAVE_FAACDECCONFIGURATION_DOWNMATRIX
+	config->downMatrix = 1;
+#endif
+#ifdef HAVE_FAACDECCONFIGURATION_DONTUPSAMPLEIMPLICITSBR
+	config->dontUpSampleImplicitSBR = 0;
+#endif
+	faacDecSetConfiguration(decoder,config);
+
+	af->bits = 16;
+
+	mp4Buffer = NULL;
+	mp4BufferSize = 0;
+	mp4ff_get_decoder_config(mp4fh,track,&mp4Buffer,&mp4BufferSize);
+
+	if(faacDecInit2(decoder,mp4Buffer,mp4BufferSize,&sampleRate,&channels)
+			< 0)
+	{
+		ERROR("Error initializing AAC decoder library.\n");
+		faacDecClose(decoder);
+		mp4ff_close(mp4fh);
+		free(mp4cb);
+		fclose(fh);
+		return -1;
+	}
+
+	af->sampleRate = sampleRate;
+	af->channels = channels;
+	time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
+	scale = mp4ff_time_scale(mp4fh,track);
+
+	if(mp4Buffer) free(mp4Buffer);
+
+	if(scale < 0) {
+		ERROR("Error getting audio format of mp4 AAC track.\n");
+		faacDecClose(decoder);
+		mp4ff_close(mp4fh);
+		fclose(fh);
+		free(mp4cb);
+		return -1;
+	}
+	cb->totalTime = ((float)time)/scale;
+
+	numSamples = mp4ff_num_samples(mp4fh,track);
+
+	dc->state = DECODE_STATE_DECODE;
+	dc->start = 0;
+	time = 0.0;
+
+	seekTable = malloc(sizeof(float)*numSamples);
+
+	for(sampleId=0; sampleId<numSamples && !eof; sampleId++) {
+		if(dc->seek && seekTableEnd>1 && 
+				seekTable[seekTableEnd]>=dc->seekWhere)
+		{
+			int i = 2;
+			while(seekTable[i]<dc->seekWhere) i++;
+			sampleId = i-1;
+			time = seekTable[sampleId];
+		}
+
+		dur = mp4ff_get_sample_duration(mp4fh,track,sampleId);
+		offset = mp4ff_get_sample_offset(mp4fh,track,sampleId);
+
+		if(sampleId>seekTableEnd) {
+			seekTable[sampleId] = time;
+			seekTableEnd = sampleId;
+		}
+
+		if(sampleId==0) dur = 0;
+		if(offset>dur) dur = 0;
+		else dur-=offset;
+		time+=((float)dur)/scale;
+
+		if(dc->seek && time>dc->seekWhere) seekPositionFound = 1;
+
+		if(dc->seek && seekPositionFound) {
+			seekPositionFound = 0;
+			chunkLen = 0;
+			cb->end = 0;
+			cb->wrap = 0;
+			dc->seek = 0;
+		}
+
+		if(dc->seek) continue;
+		
+		if(mp4ff_read_sample(mp4fh,track,sampleId,&mp4Buffer,
+				&mp4BufferSize) == 0)
+		{
+			eof = 1;
+			continue;
+		}
+
+		sampleBuffer = faacDecDecode(decoder,&frameInfo,mp4Buffer,
+						mp4BufferSize);
+		if(mp4Buffer) free(mp4Buffer);
+		if(frameInfo.error > 0) {
+			eof = 1;
+			break;
+		}
+
+		if(channels*(dur+offset) > frameInfo.samples) {
+			dur = frameInfo.samples;
+			offset = 0;
+		}
+
+		sampleCount = (unsigned long)(dur*channels);
+
+		if(sampleCount>0) {
+			initial =0;
+			bitRate = frameInfo.bytesconsumed*8.0*
+				frameInfo.channels*scale/
+				frameInfo.samples/1024+0.5;
+		}
+			
+
+		sampleBufferLen = sampleCount*2;
+
+		sampleBuffer+=offset*channels*2;
+
+		while(sampleBufferLen>0 && !dc->seek) {
+			size_t size = sampleBufferLen>CHUNK_SIZE-chunkLen ? 
+							CHUNK_SIZE-chunkLen:
+							sampleBufferLen;
+			while(cb->begin==cb->end && cb->wrap &&
+					!dc->stop && !dc->seek)
+			{
+					usleep(10000);
+			}
+			if(dc->stop) {
+				eof = 1;
+				break;
+			}
+			else if(!dc->seek) {
+				sampleBufferLen-=size;
+				memcpy(cb->chunks+cb->end*CHUNK_SIZE+chunkLen,
+						sampleBuffer,size);
+				cb->times[cb->end] = time;
+				cb->bitRate[cb->end] = bitRate;
+				sampleBuffer+=size;
+				chunkLen+=size;
+				if(chunkLen>=CHUNK_SIZE) {
+					cb->chunkSize[cb->end] = CHUNK_SIZE;
+					++cb->end;
+		
+					if(cb->end>=buffered_chunks) {
+						cb->end = 0;
+						cb->wrap = 1;
+					}
+					chunkLen = 0;
+				}
+			}
+		}
+	}
+
+	if(!dc->stop && !dc->seek && chunkLen>0) {
+		cb->chunkSize[cb->end] = chunkLen;
+		++cb->end;
+	
+		if(cb->end>=buffered_chunks) {
+			cb->end = 0;
+			cb->wrap = 1;
+		}
+		chunkLen = 0;
+	}
+
+	free(seekTable);
+	faacDecClose(decoder);
+	mp4ff_close(mp4fh);
+	fclose(fh);
+	free(mp4cb);
+
+	if(dc->seek) dc->seek = 0;
+
+	if(dc->stop) {
+		dc->state = DECODE_STATE_STOP;
+		dc->stop = 0;
+	}
+	else dc->state = DECODE_STATE_STOP;*/
+
+	return 0;
+}
+
+#endif /* HAVE_FAAD */
diff --git a/src/aac_decode.h b/src/aac_decode.h
new file mode 100644
index 000000000..ad0d75d75
--- /dev/null
+++ b/src/aac_decode.h
@@ -0,0 +1,36 @@
+/* the Music Player Daemon (MPD)
+ * (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
+ * This project's homepage is: http://www.musicpd.org
+ * 
+ * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
+ * 
+ * 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
+ */
+
+#ifndef AAC_DECODE_H
+#define AAC_DECODE_H
+
+#include "../config.h"
+
+#ifdef HAVE_FAAD
+
+#include "playerData.h"
+
+int getAacTotalTime(char * file);
+
+int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
+
+#endif /* HAVE_FAAD */
+
+#endif
diff --git a/src/directory.c b/src/directory.c
index 673754044..2d672afce 100644
--- a/src/directory.c
+++ b/src/directory.c
@@ -548,7 +548,8 @@ int readDirectoryDB() {
 				else if(0==strncmp(DIRECTORY_FS_CHARSET,buffer,
 						strlen(DIRECTORY_FS_CHARSET)))
 				{
-					char * fsCharset; 
+					char * fsCharset;
+					char * tempCharset; 
 
 					if(foundFsCharset) {
 						ERROR("already found "
@@ -560,15 +561,14 @@ int readDirectoryDB() {
 
 					fsCharset = &(buffer[strlen(
 							DIRECTORY_FS_CHARSET)]);
-					if(getConf()[CONF_FS_CHARSET] && 
-							strcmp(fsCharset,
-							getFsCharset())) 
+					if((tempCharset = 
+						getConf()[CONF_FS_CHARSET]) && 
+						strcmp(fsCharset,tempCharset))
 					{
 						ERROR("Using \"%s\" for the "
 							"filesystem charset "
 							"instead of \"%s\"\n",
-							fsCharset,
-							getFsCharset());
+							fsCharset,tempCharset);
 						ERROR("maybe you need to "
 							"recreate the db?\n");
 						setFsCharset(fsCharset);
diff --git a/src/main.c b/src/main.c
index 20bb06cbe..6fbb14d0b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -69,12 +69,12 @@ void usage(char * argv[]) {
                         SYSTEM_CONFIG_FILE_LOCATION);
         ERROR("\n");
         ERROR("options:\n");
-        ERROR("   --help           this usage statement\n");
-        ERROR("   --no-daemon      don't detach from console\n");
-        ERROR("   --create-db      force (re)creation database\n");
-        ERROR("   --no-create-db   don't create database\n");
-        ERROR("   --verbose        verbose logging\n");
-        ERROR("   --version        prints version information\n");
+        ERROR("   --help             this usage statement\n");
+        ERROR("   --no-daemon        don't detach from console\n");
+        ERROR("   --create-db        force (re)creation database\n");
+        ERROR("   --no-create-db     don't create database\n");
+        ERROR("   --verbose          verbose logging\n");
+        ERROR("   --version          prints version information\n");
 }
 
 void version() {
diff --git a/src/mp4_decode.h b/src/mp4_decode.h
index 14d0e495c..58d40aeff 100644
--- a/src/mp4_decode.h
+++ b/src/mp4_decode.h
@@ -19,7 +19,7 @@
  */
 
 #ifndef MP4_DECODE_H
-#define MP$_DECODE_H
+#define MP4_DECODE_H
 
 #include "../config.h"
 
diff --git a/src/path.c b/src/path.c
index 5a73baa86..e209b671d 100644
--- a/src/path.c
+++ b/src/path.c
@@ -87,40 +87,52 @@ char * getFsCharset() {
 }
 
 void initPaths() {
-#ifdef HAVE_LOCALE
-#ifdef HAVE_LANGINFO
-	char * originalLocale;
-#endif
-#endif
 	char * charset = NULL;
+	char * originalLocale;
 
 	if(getConf()[CONF_FS_CHARSET]) {
 		charset = strdup(getConf()[CONF_FS_CHARSET]);
 	}
 #ifdef HAVE_LOCALE
 #ifdef HAVE_LANGINFO
-	else if((originalLocale = setlocale(LC_CTYPE,""))) {
+	else if((originalLocale = setlocale(LC_CTYPE,NULL))) {
 		char * temp;
+		char * currentLocale;
+		originalLocale = strdup(originalLocale);
 
-		if((temp = nl_langinfo(CODESET))) {
-			charset = strdup(temp);
+		if(!(currentLocale = setlocale(LC_CTYPE,""))) {
+			ERROR("problems setting current locale with "
+					"setlocale()\n");
 		}
-		else ERROR("problems getting charset for locale\n");
-		if(!setlocale(LC_CTYPE,originalLocale)) {
-			ERROR("problems resetting locale with setlocale()\n");
+		else {
+			if(strcmp(currentLocale,"C")==0 ||
+					strcmp(currentLocale,"POSIX")==0) 
+			{
+				ERROR("current locale is \"%s\"\n",
+						currentLocale);
+			}
+			else if((temp = nl_langinfo(CODESET))) {
+				charset = strdup(temp);
+			}
+			else ERROR("problems getting charset for locale\n");
+			if(!setlocale(LC_CTYPE,originalLocale)) {
+				ERROR("problems resetting locale with setlocale()\n");
+			}
 		}
+
+		free(originalLocale);
 	}
-#endif
-#endif
 	else ERROR("problems getting locale with setlocale()\n");
+#endif
+#endif
 
 	if(charset) {
 		setFsCharset(charset);
 		free(charset);
 	}
 	else {
-		ERROR("setting filesystem charset to UTF-8\n");
-		setFsCharset("UTF-8");
+		ERROR("setting filesystem charset to ISO-8859-1\n");
+		setFsCharset("ISO-8859-1");
 	}
 }
 
diff --git a/src/tag.c b/src/tag.c
index d8af2b49f..b16b80d72 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -23,6 +23,7 @@
 #include "mp3_decode.h"
 #include "audiofile_decode.h"
 #include "mp4_decode.h"
+#include "aac_decode.h"
 #include "utils.h"
 
 #include <sys/stat.h>
@@ -46,7 +47,6 @@
 #endif
 #endif
 #ifdef HAVE_FAAD
-#include <faad.h>
 #include "mp4ff/mp4ff.h"
 #endif
 
@@ -173,177 +173,21 @@ MpdTag * mp3TagDup(char * utf8file) {
 #endif
 
 #ifdef HAVE_FAAD
-typedef struct {
-	long bytesIntoBuffer;
-	long bytesConsumed;
-	long fileOffset;
-	unsigned char *buffer;
-	int atEof;
-	FILE *infile;
-} AacBuffer;
-
-void fillAacBuffer(AacBuffer *b) {
-	if(b->bytesConsumed > 0) {
-		int bread;
-
-		if(b->bytesIntoBuffer) {
-			memmove((void *)b->buffer,(void*)(b->buffer+
-					b->bytesConsumed),b->bytesIntoBuffer);
-		}
-
-		if(!b->atEof) {
-			bread = fread((void *)(b->buffer+b->bytesIntoBuffer),1,
-					b->bytesConsumed,b->infile);
-			if(bread!=b->bytesConsumed) b->atEof = 1;
-			b->bytesIntoBuffer+=bread;
-		}
-
-		b->bytesConsumed = 0;
-
-		if(b->bytesIntoBuffer > 3) {
-			if(memcmp(b->buffer,"TAG",3)==0) b->bytesIntoBuffer = 0;
-		}
-		if(b->bytesIntoBuffer > 11) {
-			if(memcmp(b->buffer,"LYRICSBEGIN",11)==0) {
-				b->bytesIntoBuffer = 0;
-			}
-		}
-		if(b->bytesIntoBuffer > 8) {
-			if(memcmp(b->buffer,"APETAGEX",8)==0) {
-				b->bytesIntoBuffer = 0;
-			}
-		}
-	}
-}
-
-void advanceAacBuffer(AacBuffer * b, int bytes) {
-	b->fileOffset+=bytes;
-	b->bytesConsumed = bytes;
-	b->bytesIntoBuffer-=bytes;
-}
-
-static int adtsSampleRates[] = {96000,88200,64000,48000,44100,32000,24000,22050,
-				16000,12000,11025,8000,7350,0,0,0};
-
-int adtsParse(AacBuffer * b, float * length) {
-	int frames, frameLength;
-	int tFrameLength = 0;
-	int sampleRate = 0;
-	float framesPerSec, bytesPerFrame;
-
-	/* Read all frames to ensure correct time and bitrate */
-	for(frames = 0; ;frames++) {
-		fillAacBuffer(b);
-
-		if(b->bytesIntoBuffer > 7) {
-			/* check syncword */
-			if (!((b->buffer[0] == 0xFF) && 
-				((b->buffer[1] & 0xF6) == 0xF0)))
-			{
-				break;
-			}
-
-			if(frames==0) {
-				sampleRate = adtsSampleRates[
-						(b->buffer[2]&0x3c)>>2];
-			}
-
-			frameLength =  ((((unsigned int)b->buffer[3] & 0x3)) 
-					<< 11) | (((unsigned int)b->buffer[4])  
-                			<< 3) | (b->buffer[5] >> 5);
-
-			tFrameLength+=frameLength;
-
-			if(frameLength > b->bytesIntoBuffer) break;
-
-			advanceAacBuffer(b,frameLength);
-		}
-		else break;
-	}
-
-	framesPerSec = (float)sampleRate/1024.0;
-	if(frames!=0) {
-		bytesPerFrame = (float)tFrameLength/(float)(frames*1000);
-	}
-	else bytesPerFrame = 0;
-	if(framesPerSec!=0) *length = (float)frames/framesPerSec;
-
-	return 1;
-}
-
-#define AAC_MAX_CHANNELS	6
-
 MpdTag * aacTagDup(char * utf8file) {
 	MpdTag * ret = NULL;
-	AacBuffer b;
-	size_t fileread;
-	size_t bread;
-	size_t tagsize;
-	float length = -1;
-
-	memset(&b,0,sizeof(AacBuffer));
+	int time;
 
 	blockSignals();
 
-	b.infile = fopen(rmp2amp(utf8ToFsCharset(utf8file)),"r");
-	if(b.infile == NULL) return NULL;
+	time = getAacTotalTime(rmp2amp(utf8ToFsCharset(utf8file)));
 
-	fseek(b.infile,0,SEEK_END);
-	fileread = ftell(b.infile);
-	fseek(b.infile,0,SEEK_SET);
-
-	b.buffer = malloc(FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
-	memset(b.buffer,0,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
-
-	bread = fread(b.buffer,1,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,b.infile);
-	b.bytesIntoBuffer = bread;
-	b.bytesConsumed = 0;
-	b.fileOffset = 0;
-
-	if(bread!=FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b.atEof = 1;
-
-	tagsize = 0;
-	if(!memcmp(b.buffer,"ID3",3)) {
-		tagsize = (b.buffer[6] << 21) | (b.buffer[7] << 14) |
-				(b.buffer[8] << 7) | (b.buffer[9] << 0);
-
-		tagsize+=10;
-		advanceAacBuffer(&b,tagsize);
-		fillAacBuffer(&b);
-	}
-
-	if((b.buffer[0] == 0xFF) && ((b.buffer[1] & 0xF6) == 0xF0)) {
-		adtsParse(&b,&length);
-		fseek(b.infile,tagsize, SEEK_SET);
-
-		bread = fread(b.buffer,1,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
-				b.infile);
-		if(bread != FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b.atEof = 1;
-		else b.atEof = 0;
-		b.bytesIntoBuffer = bread;
-		b.bytesConsumed = 0;
-		b.fileOffset = tagsize;
-	}
-	else if(memcmp(b.buffer,"ADIF",4) == 0) {
-		int bitRate;
-		int skipSize = (b.buffer[4] & 0x80) ? 9 : 0;
-		bitRate = ((unsigned int)(b.buffer[4 + skipSize] & 0x0F)<<19) |
-            			((unsigned int)b.buffer[5 + skipSize]<<11) |
-            			((unsigned int)b.buffer[6 + skipSize]<<3) |
-            			((unsigned int)b.buffer[7 + skipSize] & 0xE0);
-
-		length = fileread;
-		if(length!=0) length = length*8.0/bitRate;
-	}
-
-	if(b.buffer) free(b.buffer);
-	fclose(b.infile);
-
-	if(length>=0) {
+	if(time>=0) {
 		if((ret = id3Dup(utf8file))==NULL) ret = newMpdTag();
-		ret->time = length+0.5;
+		ret->time = time;
 	}
 
+	unblockSignals();
+
 	return ret;
 }