|
CLAM-Development
1.3
|
00001 /* 00002 * Copyright (c) 2004 MUSIC TECHNOLOGY GROUP (MTG) 00003 * UNIVERSITAT POMPEU FABRA 00004 * 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 * 00020 */ 00021 00022 #if USE_MAD != 1 00023 #error with_mad was not set to 1 with scons, but you are including files that require this. Please fix your settings.cfg 00024 #endif 00025 00026 #if USE_ID3 != 1 00027 #error with_id3 was not set to 1 with scons, but you are including files that require this. Please fix your settings.cfg 00028 #endif 00029 00030 00031 #include "MpegCodec.hxx" 00032 #include "AudioFileFormats.hxx" 00033 #include "AudioFile.hxx" 00034 #include "AudioFileHeader.hxx" 00035 #include "MpegBitstream.hxx" 00036 #include "MpegAudioStream.hxx" 00037 #include <mad.h> 00038 #include <id3/tag.h> 00039 #include <cstdio> 00040 #include <iostream> 00041 #include <sys/types.h> 00042 #include <sys/stat.h> 00043 00044 namespace CLAM 00045 { 00046 00047 namespace AudioCodecs 00048 { 00049 00050 00051 /* XING parsing is from the MAD winamp input plugin */ 00052 /* Ripped mercilessly from mpg321 */ 00053 00054 struct xing { 00055 int flags; 00056 unsigned long frames; 00057 unsigned long bytes; 00058 unsigned char toc[100]; 00059 long scale; 00060 }; 00061 00062 enum { 00063 XING_FRAMES = 0x0001, 00064 XING_BYTES = 0x0002, 00065 XING_TOC = 0x0004, 00066 XING_SCALE = 0x0008 00067 }; 00068 00069 # define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g') 00070 00071 static 00072 int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen) 00073 { 00074 if (bitlen < 64) goto fail; 00075 if (mad_bit_read(&ptr, 32) != XING_MAGIC) goto fail; 00076 00077 xing->flags = mad_bit_read(&ptr, 32); 00078 bitlen -= 64; 00079 00080 if (xing->flags & XING_FRAMES) { 00081 if (bitlen < 32) goto fail; 00082 00083 xing->frames = mad_bit_read(&ptr, 32); 00084 bitlen -= 32; 00085 } 00086 00087 if (xing->flags & XING_BYTES) { 00088 if (bitlen < 32) goto fail; 00089 00090 xing->bytes = mad_bit_read(&ptr, 32); 00091 bitlen -= 32; 00092 } 00093 00094 if (xing->flags & XING_TOC) { 00095 if (bitlen < 800) goto fail; 00096 00097 // MRJ: We just need the 8 least significant bits 00098 for (unsigned i = 0; i < 100; ++i) 00099 xing->toc[i] = (unsigned char)mad_bit_read(&ptr, 8); 00100 bitlen -= 800; 00101 } 00102 00103 if (xing->flags & XING_SCALE) { 00104 if (bitlen < 32) goto fail; 00105 xing->scale = mad_bit_read(&ptr, 32); 00106 bitlen -= 32; 00107 } 00108 return 1; 00109 00110 fail: 00111 xing->flags = 0; 00112 return 0; 00113 } 00114 00115 00116 00117 MpegCodec::MpegCodec() 00118 { 00119 00120 } 00121 00122 MpegCodec::~MpegCodec() 00123 { 00124 } 00125 00126 MpegCodec& MpegCodec::Instantiate() 00127 { 00128 static MpegCodec theInstance; 00129 return theInstance; 00130 } 00131 00132 bool MpegCodec::IsReadable( std::string uri ) const 00133 { 00134 // If has extension and it is not mp3 reject it 00135 std::string::size_type startExt = uri.rfind( '.' ); 00136 if ( startExt != std::string::npos ) 00137 { 00138 std::string ext = uri.substr(startExt+1); 00139 if ( ext!="mp3" && ext!="mpg" && ext!="mpeg") 00140 return false; 00141 } 00142 00143 // If it is not readable reject it 00144 FILE* handle = fopen( uri.c_str(), "rb" ); 00145 if ( !handle ) // File doesn't exists / not readable 00146 return false; 00147 00148 // Look for an Mpeg frame 00149 MpegBitstream bitstream; 00150 bitstream.Init(handle); 00151 bool foundSomeMpegFrame = false; 00152 while( !foundSomeMpegFrame 00153 && !bitstream.EOS() && !bitstream.FatalError() ) 00154 foundSomeMpegFrame = bitstream.NextFrame(); 00155 bitstream.Finish(); 00156 fclose( handle ); 00157 return foundSomeMpegFrame; 00158 } 00159 00160 bool MpegCodec::IsWritable( std::string uri, const AudioFileHeader& header ) const 00161 { 00162 // CLAM does not encode Mpeg 00163 return false; 00164 } 00165 00166 Stream* MpegCodec::GetStreamFor( const AudioFile& file ) 00167 { 00168 return new MpegAudioStream(file); 00169 } 00170 00171 void MpegCodec::RetrieveHeaderData( std::string uri, AudioFileHeader& hdr ) 00172 { 00173 00174 FILE* handle = fopen( uri.c_str(), "rb" ); 00175 00176 if ( !handle ) // File doesn't exists / not readable 00177 return; 00178 00179 struct stat fileStats; 00180 00181 if ( stat( uri.c_str(), &fileStats ) != 0 ) 00182 { 00183 // Error reading stats from file 00184 fclose(handle); 00185 return; 00186 } 00187 00188 unsigned long fileLength = fileStats.st_size; 00189 00190 if ( fseek( handle, -128, SEEK_END ) < 0 ) 00191 { 00192 /* File empty */ 00193 fclose(handle); 00194 return; 00195 } 00196 00197 char buffer[3]; 00198 00199 if ( fread( buffer, 1, 3, handle ) != 3 ) 00200 { 00201 fclose(handle); 00202 return; 00203 } 00204 00205 if ( !strncmp( buffer, "TAG", 3 ) ) 00206 { 00207 fileLength -=128; 00208 } 00209 00210 fclose( handle ); 00211 handle = fopen( uri.c_str(), "rb" ); 00212 00213 hdr.AddSampleRate(); 00214 hdr.AddChannels(); 00215 hdr.AddSamples(); 00216 hdr.AddFormat(); 00217 hdr.AddEncoding(); 00218 hdr.AddEndianess(); 00219 hdr.AddLength(); 00220 hdr.UpdateData(); 00221 00222 MpegBitstream bitstream; 00223 00224 bitstream.Init(handle); 00225 00226 int frameCount = 0; 00227 struct xing xingHeader; 00228 xingHeader.frames=0; 00229 bool hasXingHeader = false; 00230 bool isVBR = false; 00231 unsigned int bitrate = 0; 00232 00233 /* There are three ways of calculating the length of an mp3: 00234 1) Constant bitrate: One frame can provide the information 00235 needed: # of frames and duration. Just see how long it 00236 is and do the division. 00237 2) Variable bitrate: Xing tag. It provides the number of 00238 frames. Each frame has the same number of samples, so 00239 just use that. 00240 3) All: Count up the frames and duration of each frames 00241 by decoding each one. We do this if we've no other 00242 choice, i.e. if it's a VBR file with no Xing tag. 00243 */ 00244 00245 long numFrames = 0; 00246 00247 while ( !bitstream.FatalError() && bitstream.NextFrame() ) 00248 { 00249 if ( frameCount == 0 ) // first frame, for retrieving info about encoding 00250 { 00251 RetrieveMPEGFrameInfo( bitstream.CurrentFrame(), 00252 hdr ); 00253 if ( parse_xing( &xingHeader, 00254 bitstream.StreamState().anc_ptr, 00255 bitstream.StreamState().anc_bitlen ) ) 00256 { 00257 isVBR = true; 00258 00259 if ( xingHeader.flags & XING_FRAMES ) 00260 { 00261 /* We use the Xing tag only for frames. If it doesn't have that 00262 information, it's useless to us and we have to treat it as a 00263 normal VBR file */ 00264 hasXingHeader = true; 00265 numFrames = xingHeader.frames; 00266 break; 00267 } 00268 } 00269 bitrate = bitstream.CurrentFrame().header.bitrate; 00270 } 00271 00272 if ( frameCount <= 20 ) 00273 { 00274 if ( bitstream.CurrentFrame().header.bitrate != bitrate ) 00275 isVBR = true; 00276 } 00277 00278 if ( !isVBR && frameCount > 20 ) 00279 break; 00280 00281 frameCount++; 00282 } 00283 00284 if ( !isVBR ) 00285 { 00286 double time = ( fileLength * 8.0 ) / bitstream.CurrentFrame().header.bitrate; 00287 double timeFrac = (double)time - ((long)(time)); 00288 long nsamples = 32 * MAD_NSBSAMPLES(&bitstream.CurrentFrame().header); // samples per frame 00289 numFrames = ( long) ( time * bitstream.CurrentFrame().header.samplerate / nsamples ); 00290 mad_timer_t madFmtTime; 00291 mad_timer_set( &madFmtTime, (long)time, (long)(timeFrac*100), 100 ); 00292 bitstream.Finish(); 00293 00294 //std::cerr << "Not VBR: " << (TTime)mad_timer_count( madFmtTime, MAD_UNITS_MILLISECONDS )/1000. << std::endl; 00295 hdr.SetLength( (TTime)mad_timer_count( madFmtTime, MAD_UNITS_MILLISECONDS ) ); 00296 } 00297 else if ( hasXingHeader ) 00298 { 00299 mad_timer_multiply( &bitstream.CurrentFrame().header.duration, numFrames ); 00300 mad_timer_t madFmtTime = bitstream.CurrentFrame().header.duration; 00301 bitstream.Finish(); 00302 00303 //std::cerr << "Has XING Header: "<< (TTime)mad_timer_count( madFmtTime, MAD_UNITS_MILLISECONDS )/1000. << std::endl; 00304 hdr.SetLength( (TTime)mad_timer_count( madFmtTime, MAD_UNITS_MILLISECONDS ) ); 00305 } 00306 else 00307 { 00308 00309 TTime decodedFramesLength = bitstream.Finish(); 00310 //std::cerr << "Brute force time guessing: " << decodedFramesLength/1000. << " s" << std::endl; 00311 hdr.SetLength( decodedFramesLength ); 00312 } 00313 00314 // @TODO@: Find a way to estimate reasonably well the actual 00315 // number of samples. 00316 hdr.SetSamples( TSize((hdr.GetLength()/1000.)*hdr.GetSampleRate()) ); 00317 hdr.SetEndianess( EAudioFileEndianess::eDefault ); 00318 00319 fclose( handle ); 00320 } 00321 00322 void MpegCodec::RetrieveMPEGFrameInfo( const struct mad_frame& MPEGFrame, 00323 AudioFileHeader& header ) 00324 { 00325 switch( MPEGFrame.header.layer ) 00326 { 00327 case MAD_LAYER_I: 00328 header.SetFormat( EAudioFileFormat::eMpegLayer1 ); 00329 break; 00330 case MAD_LAYER_II: 00331 header.SetFormat( EAudioFileFormat::eMpegLayer2 ); 00332 break; 00333 case MAD_LAYER_III: 00334 header.SetFormat( EAudioFileFormat::eMpegLayer3 ); 00335 break; 00336 default: 00337 break; 00338 } 00339 00340 switch( MPEGFrame.header.emphasis ) 00341 { 00342 case MAD_EMPHASIS_NONE: 00343 header.SetEncoding( EAudioFileEncoding::eDefault ); 00344 break; 00345 case MAD_EMPHASIS_50_15_US: 00346 header.SetEncoding( EAudioFileEncoding::e5015US ); 00347 break; 00348 case MAD_EMPHASIS_CCITT_J_17: 00349 header.SetEncoding( EAudioFileEncoding::eCCITTJ17 ); 00350 break; 00351 default: 00352 break; 00353 } 00354 00355 header.SetSampleRate( TData(MPEGFrame.header.samplerate) ); 00356 header.SetChannels( MAD_NCHANNELS(&MPEGFrame.header) ); 00357 } 00358 00359 00360 static const char * getField(ID3_Tag & tag, const ID3_FrameID & field) 00361 { 00362 ID3_Frame* fieldFrame = tag.Find( field ); 00363 if (not fieldFrame) return 0; 00364 ID3_Field* fieldString = fieldFrame->GetField( ID3FN_TEXT ); 00365 if (not fieldString) return 0; 00366 return fieldString->GetRawText(); 00367 } 00368 00369 void MpegCodec::RetrieveTextDescriptors( std::string uri, AudioTextDescriptors& txt ) 00370 { 00371 ID3_Tag fileTag; 00372 fileTag.Link( uri.c_str() ); 00373 00374 const char * artist = getField(fileTag, ID3FID_LEADARTIST); 00375 const char * title = getField(fileTag, ID3FID_TITLE); 00376 const char * album = getField(fileTag, ID3FID_ALBUM); 00377 const char * tracknum = getField(fileTag, ID3FID_TRACKNUM); 00378 const char * composer = getField(fileTag, ID3FID_COMPOSER); 00379 const char * performer = getField(fileTag, ID3FID_CONDUCTOR); 00380 00381 if (artist) txt.AddArtist(); 00382 if (title) txt.AddTitle(); 00383 if (album) txt.AddAlbum(); 00384 if (tracknum) txt.AddTrackNumber(); 00385 if (composer) txt.AddComposer(); 00386 if (performer) txt.AddPerformer(); 00387 00388 txt.UpdateData(); 00389 00390 if (artist) txt.SetArtist(artist); 00391 if (title) txt.SetTitle(title); 00392 if (album) txt.SetAlbum(album); 00393 if (tracknum) txt.SetTrackNumber(tracknum); 00394 if (composer) txt.SetComposer(composer); 00395 if (performer) txt.SetPerformer(performer); 00396 } 00397 } 00398 00399 } 00400
1.7.6.1