00001
00006
00007
00008 #include <cassert>
00009 #include "mp3frame.h"
00010 #include "mp3stream.h"
00011 #include "except.h"
00012
00013 #ifdef DEBUG
00014 #include <iostream>
00015 #endif
00016
00017 MP3Frame::MP3Frame(MP3Stream *stream, MP3Frame *prev)
00018 {
00019 m_stream = stream;
00020 m_corruption = false;
00021 m_firstframe = (prev == 0);
00022 SetZeroes();
00023
00024 while(!Init(prev))
00025 {
00026 Cleanup();
00027 SetZeroes();
00028 }
00029
00030 #ifdef DEBUG
00031 std::cout << "newframe @" << m_totalbytes << ", size " << m_spacesize << ", data " << m_datasize << " begin -" << m_databegin << std::endl;
00032 #endif
00033 }
00034
00035 MP3Frame::~MP3Frame()
00036 {
00037 Cleanup();
00038 }
00039
00040 void MP3Frame::Cleanup()
00041 {
00042 delete m_fh;
00043 delete m_dh;
00044 delete m_ch[0][0];
00045 delete m_ch[0][1];
00046 delete m_ch[1][0];
00047 delete m_ch[1][1];
00048 delete m_data;
00049 }
00050
00051 void MP3Frame::SetZeroes()
00052 {
00053
00054 m_fh = 0;
00055 m_dh = 0;
00056 m_ch[0][0] = m_ch[0][1] = m_ch[1][0] = m_ch[1][1] = 0;
00057 m_data = 0;
00058 m_next = 0;
00059 m_spacesize = m_datasize = m_databegin = 0;
00060 m_framesize = m_newdatabegin = m_stuffing = 0;
00061 m_sizechange = 0;
00062 m_locked = false;
00063 }
00064
00065 bool MP3Frame::Init(MP3Frame *prev)
00066 {
00067 int headersize = mp3::syncbits;
00068 Bitstream &bs = m_stream->GetBitstream();
00069
00070 try {
00071 int garbage = bs.Find(mp3::sync, mp3::syncbits);
00072
00073 if(garbage)
00074 {
00075 #ifdef DEBUG
00076 std::cout << "corruption: garbage (" << garbage << ')' << std::endl;
00077 #endif
00078
00079 m_corruption = !m_firstframe;
00080 }
00081
00082 m_fh = new FrameHeader(bs);
00083
00084 #ifdef DEBUG
00085 std::cout << "frameheader: V" << m_fh->Version() << " L" << m_fh->Layer() << ' ' << m_fh->Bitrate() << "kbps" << std::endl;
00086 #endif
00087
00088 if(!m_fh->isValid())
00089 {
00090 #ifdef DEBUG
00091 std::cout << "corruption: invalid frame header" << std::endl;
00092 #endif
00093
00094 m_corruption = true;
00095 return false;
00096 }
00097
00098
00099 if(m_fh->isCRC())
00100 {
00101 #ifdef DEBUG
00102 std::cout << "CRC code found" << std::endl;
00103 #endif
00104
00105 bs.Read(&m_CRC, mp3::CRCbits);
00106 headersize += mp3::CRCbits;
00107 }
00108
00109
00110 if(m_fh->Version() == 1)
00111 if(m_fh->NumChannels() == 1)
00112 m_dh = new DataHeaderMPEG1Mono(bs);
00113 else
00114 m_dh = new DataHeaderMPEG1Stereo(bs);
00115 else
00116 if(m_fh->NumChannels() == 1)
00117 m_dh = new DataHeaderMPEG2Mono(bs);
00118 else
00119 m_dh = new DataHeaderMPEG2Stereo(bs);
00120
00121 headersize += m_fh->Size() + m_dh->Size();
00122 m_framesize = m_fh->FrameSize();
00123 m_databegin = m_dh->DataBegin();
00124
00125
00126 for(int i = 0; i < m_fh->NumGranules(); i++)
00127 for(int j = 0; j < m_fh->NumChannels(); j++)
00128 {
00129 if(m_fh->Version() == 1)
00130 m_ch[i][j] = new ChannelHeaderMPEG1(bs);
00131 else
00132 m_ch[i][j] = new ChannelHeaderMPEG2(bs);
00133
00134 headersize += m_ch[i][j]->Size();
00135 m_datasize += m_ch[i][j]->DataSize();
00136 }
00137
00138 m_datasize = (m_datasize + 7) >> 3;
00139 m_spacesize = m_fh->FrameSize() - (headersize >> 3);
00140
00141 m_totalbytes = prev ? (prev->m_totalbytes + prev->m_spacesize) : 0;
00142
00143
00144 if( (prev ? (prev->m_totalbytes - prev->m_databegin + prev->m_datasize) : 0) > m_totalbytes - m_databegin ||
00145 m_datasize - m_databegin > m_spacesize )
00146 {
00147 #ifdef DEBUG
00148 std::cout << "corruption: invalid databegin -" << m_databegin << ", data " << m_datasize << std::endl;
00149 #endif
00150
00151 m_datasize = 0;
00152 m_corruption = (m_datasize != 0);
00153 }
00154
00155
00156 if( m_stream->WriteMode() == nowrite )
00157 bs.Seek(8 * m_fh->FrameSize() - headersize);
00158 else
00159 m_data = new AudioData(m_spacesize, m_datasize - m_databegin, bs);
00160
00161 return true;
00162 }
00163 catch(eEOF e)
00164 {
00165 if(e.type() == eEOF::final)
00166 {
00167 Cleanup();
00168 throw e;
00169 }
00170
00171 #ifdef DEBUG
00172 std::cout << "##########################################\n";
00173 #endif
00174
00175 m_corruption = false;
00176 m_firstframe = true;
00177 return false;
00178 }
00179 }
00180
00181 MP3Frame *MP3Frame::Destroy()
00182 {
00183 #ifdef DEBUG
00184 std::cout << "destroy @" << m_totalbytes << std::endl;
00185 #endif
00186
00187 MP3Frame *frame = m_next;
00188 delete this;
00189 return frame;
00190 }
00191
00192 MP3Frame *MP3Frame::Next()
00193 {
00194 if(!m_next)
00195 m_next = new MP3Frame(m_stream, this);
00196
00197 return m_next;
00198 }
00199
00200 void MP3Frame::WriteHeaders(Bitstream &bs)
00201 {
00202
00203 unsigned int sync = mp3::sync << (32 - mp3::syncbits);
00204 bs.Write(&sync, mp3::syncbits);
00205
00206 if(m_fh) m_fh->Write(bs);
00207 if(m_fh->isCRC()) bs.Write(&m_CRC, mp3::CRCbits);
00208 if(m_dh) m_dh->Write(bs);
00209
00210
00211 for(int i = 0; i < 2; i++)
00212 for(int j = 0; j < m_fh->NumChannels(); j++)
00213 if(m_ch[i][j]) m_ch[i][j]->Write(bs);
00214 }
00215
00216 void MP3Frame::Write(Bitstream &bs)
00217 {
00218 #ifdef DEBUG
00219 std::cout << "-----------------" << std::endl;
00220 std::cout << "writeframe @" << m_totalbytes << ", size " << m_spacesize << ", data " << m_datasize << " begin -" << m_databegin << std::endl;
00221 #endif
00222
00223 assert(m_stream->WriteMode() != nowrite);
00224
00225
00226 if(m_stream->WriteMode() == fastwrite)
00227 {
00228 WriteHeaders(bs);
00229 if(m_data) m_data->Write(bs);
00230 }
00231 else
00232 {
00233
00234 if(m_datasize - m_newdatabegin > m_spacesize)
00235 Enlarge(m_datasize - m_newdatabegin - m_spacesize);
00236
00237 m_dh->SetDataBegin(m_newdatabegin);
00238 WriteHeaders(bs);
00239
00240 m_locked = true;
00241
00242
00243 m_stream->WriteData(bs, m_spacesize + m_sizechange, m_totalbytes - m_sizechange);
00244 m_locked = false;
00245 }
00246 }
00247
00248 void MP3Frame::SetDataBegin(int startpos)
00249 {
00250 int maxdatabegin = m_dh->MaxDataBegin();
00251
00252
00253 m_newdatabegin = m_totalbytes - startpos;
00254
00255
00256 if(m_newdatabegin > maxdatabegin)
00257 {
00258 m_stuffing = m_newdatabegin - maxdatabegin;
00259 m_newdatabegin = maxdatabegin;
00260 }
00261 }
00262
00263 void MP3Frame::Enlarge(int num)
00264 {
00265
00266 while(m_fh->Bitrate() != -1 && m_sizechange < num)
00267 {
00268 m_fh->Enlarge();
00269 m_sizechange = m_fh->FrameSize() - m_framesize;
00270 }
00271
00272 if(m_fh->Bitrate() == -1)
00273 throw eCannotProceed("Cannot resize frame, it already has maximum bitrate");
00274
00275 #ifdef DEBUG
00276 std::cout << "resized @" << m_totalbytes << " to " << m_sizechange + m_spacesize << std::endl;
00277 #endif
00278 }
00279
00280 void MP3Frame::WriteData(Bitstream &bs, MP3Frame *ff, int cutstart, int cutend)
00281 {
00282
00283 int start = m_totalbytes - m_databegin - m_stuffing + cutstart;
00284
00285 int end = m_totalbytes - m_databegin + m_datasize - cutend;
00286 int stuffing = 0;
00287
00288 #ifdef DEBUG
00289 std::cout << "write @" << m_totalbytes << " of size " << m_datasize << '(' << DataSize() << ") cut " << cutstart << ' ' << cutend << std::endl;
00290 #endif
00291
00292 assert(cutstart >= 0);
00293 assert(cutend >= 0);
00294 assert(start < end);
00295
00296 if(cutstart < m_stuffing)
00297 {
00298 if(end - start < m_stuffing - cutstart)
00299 stuffing = end - start;
00300 else
00301 stuffing = m_stuffing - cutstart;
00302
00303 bs.WriteNullBytes(stuffing);
00304 start += m_stuffing - cutstart;
00305
00306 #ifdef DEBUG
00307 std::cout << "written stuffing " << stuffing << std::endl;
00308 #endif
00309 }
00310
00311 assert(start >= ff->m_totalbytes);
00312
00313 while(true)
00314 {
00315
00316 if(start < end && ff->m_totalbytes + ff->m_spacesize > start)
00317 {
00318
00319 int startbyte = (start > ff->m_totalbytes) ? (start - ff->m_totalbytes) : 0;
00320
00321 int endbyte = (end < ff->m_totalbytes + ff->m_spacesize) ? (end - ff->m_totalbytes) : ff->m_spacesize;
00322
00323 if(ff->m_data) ff->m_data->Write(bs, startbyte, endbyte);
00324
00325 #ifdef DEBUG
00326 std::cout << "written bytes " << startbyte << '-' << endbyte << " from frame @" << ff->m_totalbytes << std::endl;
00327 #endif
00328 }
00329
00330
00331 if(ff->m_next && ff->m_next->m_totalbytes < end)
00332 ff = ff->m_next;
00333 else
00334 {
00335 m_stream->SeekTo(ff);
00336 return;
00337 }
00338 }
00339 }
00340
00341 void MP3Frame::SetFirst()
00342 {
00343 m_stream->SetFirst(this);
00344 }
00345
00346 bool MP3Frame::isLocked() const
00347 {
00348 return m_locked;
00349 }
00350
00351 bool MP3Frame::CorruptionFound() const
00352 {
00353 return m_corruption;
00354 }
00355
00356 int MP3Frame::Bitrate() const
00357 {
00358 return m_fh->Bitrate();
00359 }
00360
00361 int MP3Frame::DataSize() const
00362 {
00363 return m_datasize + m_stuffing;
00364 }
00365
00366 void MP3Frame::ChangeGain(int n)
00367 {
00368
00369 for(int i = 0; i < 2; i++)
00370 for(int j = 0; j < m_fh->NumChannels(); j++)
00371 if(m_ch[i][j]) m_ch[i][j]->ChangeGain(n);
00372 }
00373
00374 bool MP3Frame::isSilent() const
00375 {
00376 int size = 0;
00377
00378
00379
00380 for(int j = 0; j < m_fh->NumChannels(); j++)
00381 size += m_ch[1][j]->DataSize();
00382
00383 return size == 0;
00384 }
00385
00386 void MP3Frame::ShowInfo(std::ostream &str) const
00387 {
00388 static const char *versiontext[] = { 0, "MPEG1", "MPEG2", "MPEG2.5" };
00389 static const char *modetext[] = { "Stereo", "Joint Stereo", "Dual Channel", "Single Channel" };
00390
00391 if( !m_fh->isValid() )
00392 str << "Invalid file!" << std::endl;
00393 else
00394 {
00395 str << "Format: " << versiontext[m_fh->Version()] << " layer " << m_fh->Layer() << std::endl;
00396 str << "Bitrate: " << m_fh->Bitrate() << " kbps" << std::endl;
00397 str << "Frequency: " << m_fh->Frequency() << " kHz" << std::endl;
00398 str << "Mode: " << modetext[m_fh->Mode()];
00399 if(m_fh->isMSstereo()) str << " MS";
00400 if(m_fh->isIntensStereo()) str << " Intensity";
00401 str << std::endl;
00402 }
00403 }