Re: [madman-discuss] Re: m4a support
Brought to you by:
inducer
From: Andreas K. <ma...@ti...> - 2004-07-28 07:46:05
|
Hi Walt, Right now I don't have as much time as I'd like, but I've briefly looked at your patch and decided that it will make it into madman eventually. I'll probably make it compile-time optional, just like I intend with FLAC support; but it will go in. Thanks for your submission! Andreas Am Mo, den 26.07.2004 schrieb Walt um 5:03: > Reading some posts by Scott Wheeler, I doubt that itunes' tagging will > be part of TagLib, so I added read support here, and I plan on looking > at writing tags. It uses faad2, which is needed for xmms to play the file. > > Walt > > in main/SConstruct: > myenv.Append(LIBS = "mp4ff") > myenv.Append(LIBS = "faad") > > diff ../../song.cpp database/song.cpp > --- ../../song.cpp 2004-07-25 22:08:06.000000000 -0400 > +++ database/song.cpp 2004-07-25 22:56:45.395108320 -0400 > @@ -49,8 +49,8 @@ > > #include <qapplication.h> > > > +#include <mp4ff.h> > +#include <faad.h> > > // private helpers > ------------------------------------------------------------ > namespace > @@ -1751,6 +1751,180 @@ > > > > +//tM4ASong > ------------------------------------------------------------------- > + > +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); > + } > + > + > + > + > +class tM4ASong : public tSong > +{ > + public: > + QString mimeType() const > + { return "audio/x-m4a"; } > + > + > + void readInfo() const; > + void setFieldText(tSongField field, QString const &value); > + > + void stripTagInternal(); > + > +}; > + > + > +int GetAACTrack(mp4ff_t *infile) > +{ > + /* find AAC track */ > + unsigned int i, rc; > + int numTracks = mp4ff_total_tracks(infile); > + for (i = 0; i < numTracks; i++) > + { > + unsigned char *buff = NULL; > + unsigned 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) > + return -1; > + return i; > + } > + > + } > + /* can't decode this */ > + return -1; > +} > + > + > + > +void tM4ASong::readInfo() const > +{ > + > + mp4ff_t *infile; > + FILE *mp4File; > + char *tag_string=NULL; > + char *tag_item=NULL; > + mp4ff_callback_t *mp4cb; > + unsigned char *buffer; > + unsigned int buffer_size; > + mp4AudioSpecificConfig mp4ASC; > + int track = 0; > + > + mp4cb = (mp4ff_callback_t *) malloc(sizeof(mp4ff_callback_t)); > + mp4File = fopen(filename().c_str(), "rb"); > + mp4cb->read = read_callback; > + mp4cb->seek = seek_callback; > + mp4cb->user_data = mp4File; > + > + infile = mp4ff_open_read(mp4cb); > + > + mp4ff_meta_get_title(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Title, > + QString::fromUtf8(tag_string), FIELD_TITLE); > + > + mp4ff_meta_get_artist(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Artist, > + QString::fromUtf8(tag_string), FIELD_ARTIST); > + > + mp4ff_meta_get_album(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Album, > + QString::fromUtf8(tag_string), > FIELD_ALBUM); > > + mp4ff_meta_get_track(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->TrackNumber, > + QString::fromUtf8(tag_string), FIELD_TRACKNUMBER); > + > + mp4ff_meta_get_genre(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Genre, > + QString::fromUtf8(tag_string), FIELD_GENRE); > + > + mp4ff_meta_get_date(infile,&tag_string); > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Year, > + QString::fromUtf8(tag_string), FIELD_YEAR); > + > + if ((track = GetAACTrack(infile)) < 0) > + { > + fprintf(stderr, "Unable to find correct AAC sound track in the MP4 > file.\n"); > + mp4ff_close(infile); > + free(mp4cb); > + fclose(mp4File); > + return; > + } > + > + buffer = NULL; > + buffer_size = 0; > + mp4ff_get_decoder_config(infile, track, &buffer, &buffer_size); > + if (buffer) > + { > + AudioSpecificConfig(buffer, buffer_size, &mp4ASC); > + free(buffer); > + } > + long samples = mp4ff_num_samples(infile,track); > + float f = 1024.0; > + float seconds; > + if ((mp4ASC.sbr_present_flag == 1) || mp4ASC.forceUpSampling) > + { > + f = f * 2.0; > + } > + seconds = (float)samples*(float)(f-1.0)/(float)mp4ASC.samplingFrequency; > + assignAndCheckForModification(this, SongCollection, > + const_cast<tM4ASong *>(this)->Duration, > + seconds, FIELD_DURATION); > + > + free(tag_string); > + mp4ff_close(infile); > + free(mp4cb); > + fclose(mp4File); > + tSong::readInfo(); > +} > + > + > + > + > +void tM4ASong::setFieldText(tSongField field, QString const &value) > +{ > + > +} > + > + > + > + > +void tM4ASong::stripTagInternal() > +{ > + > +} > + > + > + > + > // public > --------------------------------------------------------------------- > tSong *makeSong(tFilename const &filename) > { > @@ -1767,6 +1941,21 @@ > song->setFilename(filename); > return song; > } > + else if (string2QString(ext).lower() == "m4a") > + { > + tSong *song = new tM4ASong; > + song->setFilename(filename); > + return song; > + } > + > + > else if (string2QString(ext).lower() == "ogg") > { > tSong *song = new tOggSong; > > > > ------------------------------------------------------- > This SF.Net email is sponsored by BEA Weblogic Workshop > FREE Java Enterprise J2EE developer tools! > Get your free copy of BEA WebLogic Workshop 8.1 today. > http://ads.osdn.com/?ad_id=4721&alloc_id=10040&op=click > _______________________________________________ > madman-discuss mailing list > mad...@li... > https://lists.sourceforge.net/lists/listinfo/madman-discuss > |