From f409d85bbdde60c3acc175c9ad30a6f9d372e9a8 Mon Sep 17 00:00:00 2001 From: Warren Dukes Date: Thu, 18 Mar 2004 13:47:41 +0000 Subject: [PATCH] initial mp4/aac decoder, hasn't been tested at all yet, just compiles git-svn-id: https://svn.musicpd.org/mpd/trunk@275 09075e82-0dd4-0310-85a5-a0d7c8717e4f --- src/Makefile.am | 6 +- src/libid3tag/config.h.in | 6 +- src/libmad/config.h.in | 6 +- src/mp4_decode.c | 288 ++++++++++++++++++++++++++++++++++++++ src/mp4_decode.h | 42 ++++++ src/tag.c | 39 +----- 6 files changed, 342 insertions(+), 45 deletions(-) create mode 100644 src/mp4_decode.c create mode 100644 src/mp4_decode.h diff --git a/src/Makefile.am b/src/Makefile.am index a663cca7f..7e4b12090 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,12 +4,14 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \ song.h list.h directory.h tables.h utils.h path.h mp3_decode.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 + audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \ + mp4_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 $(mpd_headers) + audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \ + $(mpd_headers) mpd_CFLAGS = $(MPD_CFLAGS) mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB) diff --git a/src/libid3tag/config.h.in b/src/libid3tag/config.h.in index ba35b4be9..b4f0f8997 100644 --- a/src/libid3tag/config.h.in +++ b/src/libid3tag/config.h.in @@ -72,8 +72,6 @@ /* Define to empty if `const' does not conform to ANSI C. */ #undef const -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ #undef inline -#endif diff --git a/src/libmad/config.h.in b/src/libmad/config.h.in index a29b58209..2a9671cd2 100644 --- a/src/libmad/config.h.in +++ b/src/libmad/config.h.in @@ -125,11 +125,9 @@ /* Define to empty if `const' does not conform to ANSI C. */ #undef const -/* Define to `__inline__' or `__inline' if that's what the C compiler - calls it, or to nothing if 'inline' is not supported under any name. */ -#ifndef __cplusplus +/* Define as `__inline' if that's what the C compiler calls it, or to nothing + if it is not supported. */ #undef inline -#endif /* Define to `int' if does not define. */ #undef pid_t diff --git a/src/mp4_decode.c b/src/mp4_decode.c new file mode 100644 index 000000000..a96cc3536 --- /dev/null +++ b/src/mp4_decode.c @@ -0,0 +1,288 @@ +/* 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 + * + * 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 "mp4_decode.h" + +#ifdef HAVE_FAAD + +#include "command.h" +#include "utils.h" +#include "audio.h" +#include "log.h" +#include "pcm_utils.h" + +#include "mp4ff/mp4ff.h" + +#include +#include +#include +#include +#include + +int mp4_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 = AudioSpecificConfig(buff, buff_size, &mp4ASC); + free(buff); + if (rc < 0) continue; + return i; + } + } + + /* can't decode this */ + return -1; +} + +uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length) { + return fread(buffer, 1, length, (FILE*)user_data); +} + +uint32_t mp4_seekCallback(void *user_data, uint64_t position) { + return fseek((FILE*)user_data, position, SEEK_SET); +} + + +int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) +{ + FILE * fh; + mp4ff_t * mp4fh; + mp4ff_callback_t * mp4cb; + int32_t track; + int32_t time; + int32_t scale; + faacDecHandle decoder; + faacDecFrameInfo frameInfo; + faacDecConfigurationPtr config; + mp4AudioSpecificConfig mp4ASC; + unsigned char * mp4Buffer; + int mp4BufferSize; + unsigned int frameSize; + unsigned int useAacLength; + unsigned long sampleRate; + unsigned char channels; + long sampleId; + long numSamples; + + 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; + config->downMatrix = 1; + config->dontUpSampleImplicitSBR = 1; + 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); + frameSize = 1024; + useAacLength = 0; + + if(mp4Buffer) { + if(AudioSpecificConfig(mp4Buffer,mp4BufferSize,&mp4ASC) >= 0) { + if(mp4ASC.frameLengthFlag==1) frameSize = 960; + if(mp4ASC.sbr_present_flag==1) frameSize*= 2; + } + 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; + { + int eof = 0; + int rc; + long dur; + unsigned int sampleCount; + unsigned int delay = 0; + char * sampleBuffer; + unsigned int initial = 1; + size_t sampleBufferLen; + + for(sampleId=0; sampleIdseek) { + cb->end = 0; + cb->wrap = 0; +//#warning implement seeking here! + dc->seek = 0; + } + + dur = mp4ff_get_sample_duration(mp4fh,track,sampleId); + rc = mp4ff_read_sample(mp4fh,track,sampleId,&mp4Buffer, + &mp4BufferSize); + + if(rc==0) eof = 1; + else { + sampleBuffer = faacDecDecode(decoder, + &frameInfo, + mp4Buffer, + mp4BufferSize); + if(mp4Buffer) free(mp4Buffer); + if(sampleId==0) dur = 0; + if(useAacLength || scale!=sampleRate) { + sampleCount = frameInfo.samples; + } + else { + sampleCount = (unsigned long)(dur * + frameInfo.channels); + if(!useAacLength && !initial && + (sampleId < numSamples/2) && + (sampleCount!= + frameInfo.samples)) + { + useAacLength = 1; + sampleCount = frameInfo.samples; + } + + if(initial && (sampleCount < frameSize* + frameInfo.channels) && + (frameInfo.samples > + sampleCount)) + { + delay = frameInfo.samples - + sampleCount; + } + + } + + if(sampleCount>0) initial =0; + sampleBufferLen = sampleCount*2; + sampleBuffer+=delay*2; + while(sampleBufferLen > 0) { + size_t size = sampleBufferLen> + CHUNK_SIZE? + CHUNK_SIZE: + sampleBufferLen; + while(cb->begin==cb->end && cb->wrap && + !dc->stop && !dc->seek) + { + usleep(10000); + } + if(dc->stop) { + eof = 1; + break; + } + else if(dc->seek) break; + +#ifdef WORDS_BIGENDIAN + pcm_changeBufferEndianness(sampleBuffer, + size,af->bits); +#endif + memcpy(cb->chunks+cb->end*CHUNK_SIZE, + sampleBuffer,size); + cb->chunkSize[cb->end] = size; + +//#warning implement time for AAC + cb->times[cb->end] = 0; + + ++cb->end; + + if(cb->end>=buffered_chunks) { + cb->end = 0; + cb->wrap = 1; + } + } + } + } + + if(dc->seek) dc->seek = 0; + + if(dc->stop) { + dc->state = DECODE_STATE_STOP; + dc->stop = 0; + } + else dc->state = DECODE_STATE_STOP; + } + + faacDecClose(decoder); + mp4ff_close(mp4fh); + fclose(fh); + free(mp4cb); + + return 0; +} + +#endif /* HAVE_FAAD */ diff --git a/src/mp4_decode.h b/src/mp4_decode.h new file mode 100644 index 000000000..14d0e495c --- /dev/null +++ b/src/mp4_decode.h @@ -0,0 +1,42 @@ +/* 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 + * + * 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 MP4_DECODE_H +#define MP$_DECODE_H + +#include "../config.h" + +#ifdef HAVE_FAAD + +#include "playerData.h" + +#include "mp4ff/mp4ff.h" + +int mp4_getAACTrack(mp4ff_t *infile); + +uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length); + +uint32_t mp4_seekCallback(void *user_data, uint64_t position); + +int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc); + +#endif /* HAVE_FAAD */ + +#endif diff --git a/src/tag.c b/src/tag.c index 1a0acb3ea..c5b012b79 100644 --- a/src/tag.c +++ b/src/tag.c @@ -22,6 +22,7 @@ #include "sig_handlers.h" #include "mp3_decode.h" #include "audiofile_decode.h" +#include "mp4_decode.h" #include "utils.h" #include @@ -173,38 +174,6 @@ MpdTag * mp3TagDup(char * utf8file) { #ifdef HAVE_FAAD /* copied from FAAD2 frontend */ -int mp4GetAACTrack(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 = AudioSpecificConfig(buff, buff_size, &mp4ASC); - free(buff); - if (rc < 0) continue; - return i; - } - } - - /* can't decode this */ - return -1; -} - -uint32_t mp4ReadCallback(void *user_data, void *buffer, uint32_t length) { - return fread(buffer, 1, length, (FILE*)user_data); -} - -uint32_t mp4SeekCallback(void *user_data, uint64_t position) { - return fseek((FILE*)user_data, position, SEEK_SET); -} - MpdTag * mp4DataDup(char * utf8file, int * mp4MetadataFound) { MpdTag * ret = NULL; FILE * fh; @@ -225,8 +194,8 @@ MpdTag * mp4DataDup(char * utf8file, int * mp4MetadataFound) { } cb = malloc(sizeof(mp4ff_callback_t)); - cb->read = mp4ReadCallback; - cb->seek = mp4SeekCallback; + cb->read = mp4_readCallback; + cb->seek = mp4_seekCallback; cb->user_data = fh; mp4fh = mp4ff_open_read(cb); @@ -237,7 +206,7 @@ MpdTag * mp4DataDup(char * utf8file, int * mp4MetadataFound) { return NULL; } - track = mp4GetAACTrack(mp4fh); + track = mp4_getAACTrack(mp4fh); if(track < 0) { mp4ff_close(mp4fh); fclose(fh);