MpegBitstream.cxx

Go to the documentation of this file.
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 #include "MpegBitstream.hxx"
00023 #include "Assert.hxx"
00024 #include <cstring>
00025 #include <iostream>
00026 #include <sstream>
00027 #include <iomanip>
00028 
00029 namespace CLAM
00030 {
00031 
00032 namespace AudioCodecs
00033 {
00034         // MRJ: This number was extracted from Underbit's own
00035         // mp3 player code ( mad-0.14.2b2, player.c:86 ). As they
00036         // say: 40000 bytes is worth 2.5 secs of audio on a stream
00037         // with 128 kpbs, 1s with 320 kbps
00038         const int MpegBitstream::mInputBufferSize = 5*8192;
00039         
00040         // Taken from alsaplayer
00041     static std::string MadError(enum mad_error error)
00042         {
00043                 switch (error) {
00044                         case MAD_ERROR_BUFLEN:
00045                         case MAD_ERROR_BUFPTR:
00046                                 /* these errors are handled specially and/or should not occur */
00047                                 break;
00048 
00049                         case MAD_ERROR_NOMEM:        return ("not enough memory");
00050                         case MAD_ERROR_LOSTSYNC:     return ("lost synchronization");
00051                         case MAD_ERROR_BADLAYER:     return ("reserved header layer value");
00052                         case MAD_ERROR_BADBITRATE:   return ("forbidden bitrate value");
00053                         case MAD_ERROR_BADSAMPLERATE:    return ("reserved sample frequency value");
00054                         case MAD_ERROR_BADEMPHASIS:  return ("reserved emphasis value");
00055                         case MAD_ERROR_BADCRC:       return ("CRC check failed");
00056                         case MAD_ERROR_BADBITALLOC:  return ("forbidden bit allocation value");
00057                         case MAD_ERROR_BADSCALEFACTOR:   return ("bad scalefactor index");
00058                         case MAD_ERROR_BADFRAMELEN:  return ("bad frame length");
00059                         case MAD_ERROR_BADBIGVALUES:     return ("bad big_values count");
00060                         case MAD_ERROR_BADBLOCKTYPE:     return ("reserved block_type");
00061                         case MAD_ERROR_BADSCFSI:     return ("bad scalefactor selection info");
00062                         case MAD_ERROR_BADDATAPTR:   return ("bad main_data_begin pointer");
00063                         case MAD_ERROR_BADPART3LEN:  return ("bad audio data length");
00064                         case MAD_ERROR_BADHUFFTABLE:     return ("bad Huffman table select");
00065                         case MAD_ERROR_BADHUFFDATA:  return ("Huffman data overrun");
00066                         case MAD_ERROR_BADSTEREO:    return ("incompatible block_type for JS");
00067                         default:;
00068                 }
00069                 std::ostringstream os;
00070                 os << "error 0x" << std::setbase(16) << std::setfill('4') << std::setw(4) << error;
00071                 return os.str();
00072         }
00073 
00074         MpegBitstream::MpegBitstream()
00075                 : mpFile(NULL)
00076         {
00077                 mInputBuffer = new unsigned char[mInputBufferSize];
00078         }
00079         
00080         MpegBitstream::~MpegBitstream()
00081         {
00082                 if ( mInputBuffer )
00083                         delete [] mInputBuffer;
00084         }
00085 
00086         void MpegBitstream::Init( FILE* fp )
00087         {
00088                 mpFile = fp;
00089                 Init();
00090         }
00091 
00092         void MpegBitstream::Init()
00093         {
00094                 mad_stream_init( &mBitstream );
00095                 mad_frame_init( &mCurrentFrame );
00096                 mad_synth_init( &mMpegSynth );
00097                 mad_timer_reset( &mStreamTimer );
00098                 mFatalError = false;
00099         }
00100 
00101         TTime MpegBitstream::Finish()
00102         {
00103                 mad_synth_finish( &mMpegSynth );
00104                 mad_frame_finish( &mCurrentFrame );
00105                 mad_stream_finish( &mBitstream );
00106 
00107                 return (TTime)mad_timer_count( mStreamTimer, MAD_UNITS_MILLISECONDS );
00108         }
00109 
00110         bool MpegBitstream::EOS()
00111         {
00112                 if ( feof( mpFile ) ) // no more frames
00113                         return true;
00114                 return false;
00115         }
00116 
00117         bool MpegBitstream::FatalError()
00118         {
00119                 return mFatalError || ferror(mpFile)!=0;
00120         }
00121 
00122         bool MpegBitstream::EnsureEnoughBufferData()
00123         {
00124                 bool firstFrameAfterSeek = mBitstream.buffer == NULL;
00125                 bool lastDecodeNeededMoreData = mBitstream.error == MAD_ERROR_BUFLEN;
00126                 if ( not firstFrameAfterSeek and not lastDecodeNeededMoreData) return true;
00127 
00128                 TSize remaining = 0;
00129                 if (not firstFrameAfterSeek)
00130                 {
00131                         remaining = mBitstream.bufend - mBitstream.next_frame;
00132                         memmove( mInputBuffer, mBitstream.next_frame, remaining );
00133                 }
00134                 unsigned char * readStart = mInputBuffer + remaining;
00135                 TSize readSize = mInputBufferSize - remaining;
00136                 mBufferFileOffset = ftell(mpFile) - remaining;
00137                 TSize actuallyRead = fread( readStart, sizeof(unsigned char), readSize, mpFile );
00138 
00139                 if ( actuallyRead == 0 ) return false; // Eof or ferror
00140                 // Less bytes than expected were read, add buffer guard
00141                 if ( actuallyRead < readSize )
00142                 {
00143                         CLAM_ASSERT( readStart + actuallyRead + MAD_BUFFER_GUARD <= mInputBuffer + mInputBufferSize,
00144                                 "Whoops! no room left for buffer guard bytes" );
00145                         // Add mad buffer guard
00146                         memset(readStart+actuallyRead, 0, MAD_BUFFER_GUARD);
00147                         actuallyRead += MAD_BUFFER_GUARD;
00148                 }
00149 
00150                 mad_stream_buffer( &mBitstream, mInputBuffer, actuallyRead+remaining );
00151                 mBitstream.error = MAD_ERROR_NONE; // DGG: Why that?
00152                 return true;
00153         }
00154 
00157         bool MpegBitstream::NextFrame()
00158         {
00159                 while( not ferror(mpFile) )
00160                 {
00161                         if (not EnsureEnoughBufferData()) return false;
00162 
00163                         int error = mad_frame_decode(&mCurrentFrame, &mBitstream);
00164                         if (error != -1) 
00165                         {
00166                                 // frame was decoded right
00167                                 // we add this frame duration to the bitstream internal timer
00168                                 mad_timer_add( &mStreamTimer, mCurrentFrame.header.duration );
00169                                 return true;
00170                         }
00171 
00172                         if ( MAD_RECOVERABLE( mBitstream.error ) )
00173                         {
00174 //                              std::cerr << "MP3 recoverable error ignored: " << MadError(mBitstream.error) << std::endl;
00175                                 continue; // Recoverable error, ignore
00176                         }
00177                         if ( mBitstream.error == MAD_ERROR_BUFLEN )     continue; // Not enough data, take more
00178                         // Some fatal error happened!
00179                         mFatalError = true;
00180                         std::cerr << "MP3 fatal error: " << MadError(mBitstream.error) << std::endl;
00181                         return false;
00182                 }
00183                 return false; // file error
00184         }
00185 
00186         unsigned long MpegBitstream::CurrentFrameFileOffset() const
00187         {
00188                 unsigned long frameOffset = mBitstream.this_frame - mInputBuffer;
00189                 return mBufferFileOffset + frameOffset;
00190         }
00191 
00192         void MpegBitstream::SynthesizeCurrent()
00193         {
00194                 mad_synth_frame( &mMpegSynth, &mCurrentFrame );
00195         }
00196 
00197         struct mad_frame& MpegBitstream::CurrentFrame()
00198         {
00199                 return mCurrentFrame;
00200         }
00201 
00202         struct mad_synth& MpegBitstream::CurrentSynthesis()
00203         {
00204                 return mMpegSynth;
00205         }
00206         
00207 }
00208 
00209 }
00210 
Generated by  doxygen 1.6.3