MpegCodec.cxx
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
00052
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
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
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
00144 FILE* handle = fopen( uri.c_str(), "rb" );
00145 if ( !handle )
00146 return false;
00147
00148
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
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 )
00177 return;
00178
00179 struct stat fileStats;
00180
00181 if ( stat( uri.c_str(), &fileStats ) != 0 )
00182 {
00183
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
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
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 long numFrames = 0;
00246
00247 while ( !bitstream.FatalError() && bitstream.NextFrame() )
00248 {
00249 if ( frameCount == 0 )
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
00262
00263
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);
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
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
00304 hdr.SetLength( (TTime)mad_timer_count( madFmtTime, MAD_UNITS_MILLISECONDS ) );
00305 }
00306 else
00307 {
00308
00309 TTime decodedFramesLength = bitstream.Finish();
00310
00311 hdr.SetLength( decodedFramesLength );
00312 }
00313
00314
00315
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