MP3StreamState Class Reference

#include <MP3StreamState.hh>

Collaboration diagram for MP3StreamState:

Collaboration graph
[legend]

Public Member Functions

 MP3StreamState (UsageEnvironment &env)
virtual ~MP3StreamState ()
void assignStream (FILE *fid, unsigned fileSize)
unsigned findNextHeader (struct timeval &presentationTime)
Boolean readFrame (unsigned char *outBuf, unsigned outBufSize, unsigned &resultFrameSize, unsigned &resultDurationInMicroseconds)
void getAttributes (char *buffer, unsigned bufferSize) const
float filePlayTime () const
unsigned fileSize () const
void setPresentationTimeScale (unsigned scale)
unsigned getByteNumberFromPositionFraction (float fraction)
void seekWithinFile (unsigned seekByteNumber)
void checkForXingHeader ()

Protected Member Functions

unsigned readFromStream (unsigned char *buf, unsigned numChars)

Private Member Functions

MP3FrameParamsfr ()
MP3FrameParams const & fr () const
timeval currentFramePlayTime () const
Boolean findNextFrame ()

Private Attributes

UsageEnvironmentfEnv
FILE * fFid
Boolean fFidIsReallyASocket
unsigned fFileSize
unsigned fNumFramesInFile
unsigned fPresentationTimeScale
Boolean fIsVBR
Boolean fHasXingTOC
u_int8_t fXingTOC [XING_TOC_LENGTH]
MP3FrameParams fCurrentFrame
timeval fNextFramePresentationTime

Detailed Description

Definition at line 41 of file MP3StreamState.hh.


Constructor & Destructor Documentation

MP3StreamState::MP3StreamState ( UsageEnvironment env  ) 

Definition at line 34 of file MP3StreamState.cpp.

00035   : fEnv(env), fFid(NULL), fPresentationTimeScale(1) {
00036 }

MP3StreamState::~MP3StreamState (  )  [virtual]

Definition at line 38 of file MP3StreamState.cpp.

References CloseInputFile(), closeSocket, fFid, fFidIsReallyASocket, and NULL.

00038                                 {
00039   // Close our open file or socket:
00040   if (fFid != NULL && fFid != stdin) {
00041     if (fFidIsReallyASocket) {
00042       intptr_t fid_long = (intptr_t)fFid;
00043       closeSocket((int)fid_long);
00044     } else {
00045       CloseInputFile(fFid);
00046     }
00047   }
00048 }


Member Function Documentation

void MP3StreamState::assignStream ( FILE *  fid,
unsigned  fileSize 
)

Definition at line 50 of file MP3StreamState.cpp.

References False, fFid, fFidIsReallyASocket, fFileSize, fHasXingTOC, fIsVBR, fNextFramePresentationTime, fNumFramesInFile, and NULL.

Referenced by MP3FileSource::assignStream().

00050                                                               {
00051   fFid = fid;
00052 
00053   if (fileSize == (unsigned)(-1)) { /*HACK#####*/
00054     fFidIsReallyASocket = 1;
00055     fFileSize = 0;
00056   } else {
00057     fFidIsReallyASocket = 0;
00058     fFileSize = fileSize;
00059   }
00060   fNumFramesInFile = 0; // until we know otherwise
00061   fIsVBR = fHasXingTOC = False; // ditto
00062 
00063   // Set the first frame's 'presentation time' to the current wall time:
00064   gettimeofday(&fNextFramePresentationTime, NULL);
00065 }

unsigned MP3StreamState::findNextHeader ( struct timeval &  presentationTime  ) 

Definition at line 119 of file MP3StreamState.cpp.

References currentFramePlayTime(), findNextFrame(), fNextFramePresentationTime, fPresentationTimeScale, fr(), MP3FrameParams::hdr, and MILLION.

Referenced by MP3FileSource::doGetNextFrame1(), and MP3FileSource::initializeStream().

00119                                                                         {
00120   presentationTime = fNextFramePresentationTime;
00121 
00122   if (!findNextFrame()) return 0;
00123 
00124   // From this frame, figure out the *next* frame's presentation time:
00125   struct timeval framePlayTime = currentFramePlayTime();
00126   if (fPresentationTimeScale > 1) {
00127     // Scale this value
00128     unsigned secondsRem = framePlayTime.tv_sec % fPresentationTimeScale;
00129     framePlayTime.tv_sec -= secondsRem;
00130     framePlayTime.tv_usec += secondsRem*MILLION;
00131     framePlayTime.tv_sec /= fPresentationTimeScale;
00132     framePlayTime.tv_usec /= fPresentationTimeScale;
00133   }
00134   fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec;
00135   fNextFramePresentationTime.tv_sec
00136     += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION;
00137   fNextFramePresentationTime.tv_usec %= MILLION;
00138 
00139   return fr().hdr;
00140 }

Boolean MP3StreamState::readFrame ( unsigned char *  outBuf,
unsigned  outBufSize,
unsigned &  resultFrameSize,
unsigned &  resultDurationInMicroseconds 
)

Definition at line 142 of file MP3StreamState.cpp.

References currentFramePlayTime(), False, fr(), MP3FrameParams::frameSize, MP3FrameParams::hdr, MILLION, and True.

Referenced by MP3FileSource::doGetNextFrame1().

00144                                                                           {
00145   /* We assume that "mp3FindNextHeader()" has already been called */
00146 
00147   resultFrameSize = 4 + fr().frameSize;
00148 
00149   if (outBufSize < resultFrameSize) {
00150 #ifdef DEBUG_ERRORS
00151     fprintf(stderr, "Insufficient buffer size for reading input frame (%d, need %d)\n",
00152             outBufSize, resultFrameSize);
00153 #endif
00154     if (outBufSize < 4) outBufSize = 0;
00155     resultFrameSize = outBufSize;
00156 
00157     return False;
00158   }
00159 
00160   if (resultFrameSize >= 4) {
00161     unsigned& hdr = fr().hdr;
00162     *outBuf++ = (unsigned char)(hdr>>24);
00163     *outBuf++ = (unsigned char)(hdr>>16);
00164     *outBuf++ = (unsigned char)(hdr>>8);
00165     *outBuf++ = (unsigned char)(hdr);
00166 
00167     memmove(outBuf, fr().frameBytes, resultFrameSize-4);
00168   }
00169 
00170   struct timeval const pt = currentFramePlayTime();
00171   resultDurationInMicroseconds = pt.tv_sec*MILLION + pt.tv_usec;
00172 
00173   return True;
00174 }

void MP3StreamState::getAttributes ( char *  buffer,
unsigned  bufferSize 
) const

Definition at line 176 of file MP3StreamState.cpp.

References filePlayTime(), fIsVBR, and fr().

Referenced by MP3FileSource::getAttributes().

00176                                                                           {
00177   char const* formatStr
00178     = "bandwidth %d MPEGnumber %d MPEGlayer %d samplingFrequency %d isStereo %d playTime %d isVBR %d";
00179   unsigned fpt = (unsigned)(filePlayTime() + 0.5); // rounds to nearest integer
00180 #if defined(IRIX) || defined(ALPHA) || defined(_QNX4) || defined(IMN_PIM) || defined(CRIS)
00181   /* snprintf() isn't defined, so just use sprintf() - ugh! */
00182   sprintf(buffer, formatStr,
00183           fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo,
00184           fpt, fIsVBR);
00185 #else
00186   snprintf(buffer, bufferSize, formatStr,
00187           fr().bitrate, fr().isMPEG2 ? 2 : 1, fr().layer, fr().samplingFreq, fr().isStereo,
00188           fpt, fIsVBR);
00189 #endif
00190 }

float MP3StreamState::filePlayTime (  )  const

Definition at line 81 of file MP3StreamState.cpp.

References currentFramePlayTime(), fCurrentFrame, fFileSize, fNumFramesInFile, MP3FrameParams::frameSize, and MILLION.

Referenced by MP3FileSource::filePlayTime(), and getAttributes().

00081                                          {
00082   unsigned numFramesInFile = fNumFramesInFile;
00083   if (numFramesInFile == 0) {
00084     // Estimate the number of frames from the file size, and the
00085     // size of the current frame:
00086     numFramesInFile = fFileSize/(4 + fCurrentFrame.frameSize);
00087   }
00088 
00089   struct timeval const pt = currentFramePlayTime();
00090   return numFramesInFile*(pt.tv_sec + pt.tv_usec/(float)MILLION);
00091 }

unsigned MP3StreamState::fileSize (  )  const [inline]

Definition at line 57 of file MP3StreamState.hh.

References fFileSize.

Referenced by MP3FileSource::fileSize().

00057 { return fFileSize; }

void MP3StreamState::setPresentationTimeScale ( unsigned  scale  )  [inline]

Definition at line 58 of file MP3StreamState.hh.

References fPresentationTimeScale.

Referenced by MP3FileSource::setPresentationTimeScale().

unsigned MP3StreamState::getByteNumberFromPositionFraction ( float  fraction  ) 

Definition at line 93 of file MP3StreamState.cpp.

References fFileSize, fHasXingTOC, and fXingTOC.

Referenced by MP3FileSource::seekWithinFile().

00093                                                                          {
00094   if (fHasXingTOC) {
00095     // The file is VBR, with a Xing TOC; use it to determine which byte to seek to:
00096     float percent = fraction*100.0f;
00097     unsigned a = (unsigned)percent;
00098     if (a > 99) a = 99;
00099 
00100     unsigned fa = fXingTOC[a];
00101     unsigned fb;
00102     if (a < 99) {
00103       fb = fXingTOC[a+1];
00104     } else {
00105       fb = 256;
00106     }
00107     fraction = (fa + (fb-fa)*(percent-a))/256.0f;
00108   }
00109 
00110   return (unsigned)(fraction*fFileSize);
00111 }

void MP3StreamState::seekWithinFile ( unsigned  seekByteNumber  ) 

Definition at line 113 of file MP3StreamState.cpp.

References fFid, fFidIsReallyASocket, and SeekFile64().

Referenced by MP3FileSource::seekWithinFile().

00113                                                            {
00114   if (fFidIsReallyASocket) return; // it's not seekable
00115 
00116   SeekFile64(fFid, seekByteNumber, SEEK_SET);
00117 }

void MP3StreamState::checkForXingHeader (  ) 

Definition at line 399 of file MP3StreamState.cpp.

References fFileSize, fHasXingTOC, fIsVBR, fNumFramesInFile, fr(), MP3FrameParams::frameBytes, MP3FrameParams::frameSize, frameSize, fXingTOC, MP3FrameParams::sideInfoSize, True, XING_BYTES_FLAG, XING_FRAMES_FLAG, XING_TOC_FLAG, and XING_TOC_LENGTH.

Referenced by MP3FileSource::initializeStream().

00399                                         {
00400   // Look for 'Xing' in the first 4 bytes after the 'side info':
00401   if (fr().frameSize < fr().sideInfoSize) return;
00402   unsigned bytesAvailable = fr().frameSize - fr().sideInfoSize;
00403   unsigned char* p = &(fr().frameBytes[fr().sideInfoSize]);
00404 
00405   if (bytesAvailable < 8) return;
00406   if (p[0] != 'X' || p[1] != 'i' || p[2] != 'n' || p[3] != 'g') return;
00407 
00408   // We found it.
00409   fIsVBR = True;
00410 
00411   u_int32_t flags = (p[4]<<24) | (p[5]<<16) | (p[6]<<8) | p[7];
00412   unsigned i = 8;
00413   bytesAvailable -= 8;
00414 
00415   if (flags&XING_FRAMES_FLAG) {
00416     // The next 4 bytes are the number of frames:
00417     if (bytesAvailable < 4) return;
00418     fNumFramesInFile = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]);
00419     i += 4; bytesAvailable -= 4;
00420   }
00421 
00422   if (flags&XING_BYTES_FLAG) {
00423     // The next 4 bytes is the file size:
00424     if (bytesAvailable < 4) return;
00425     fFileSize = (p[i]<<24)|(p[i+1]<<16)|(p[i+2]<<8)|(p[i+3]);
00426     i += 4; bytesAvailable -= 4;
00427   }
00428 
00429   if (flags&XING_TOC_FLAG) {
00430     // Fill in the Xing 'table of contents':
00431     if (bytesAvailable < XING_TOC_LENGTH) return;
00432     fHasXingTOC = True;
00433     for (unsigned j = 0; j < XING_TOC_LENGTH; ++j) {
00434       fXingTOC[j] = p[i+j];
00435     }
00436     i += XING_TOC_FLAG; bytesAvailable -= XING_TOC_FLAG;
00437   }
00438 }

unsigned MP3StreamState::readFromStream ( unsigned char *  buf,
unsigned  numChars 
) [protected]

Definition at line 369 of file MP3StreamState.cpp.

References fEnv, fFid, fFidIsReallyASocket, and waitUntilSocketIsReadable().

Referenced by findNextFrame().

00370                                                            {
00371   // Hack for doing socket I/O instead of file I/O (e.g., on Windows)
00372   if (fFidIsReallyASocket) {
00373     intptr_t fid_long = (intptr_t)fFid;
00374     int sock = (int)fid_long;
00375     unsigned totBytesRead = 0;
00376     do {
00377       waitUntilSocketIsReadable(fEnv, sock);
00378       int bytesRead
00379         = recv(sock, &((char*)buf)[totBytesRead], numChars-totBytesRead, 0);
00380       if (bytesRead < 0) return 0;
00381 
00382       totBytesRead += (unsigned)bytesRead;
00383     } while (totBytesRead < numChars);
00384 
00385     return totBytesRead;
00386   } else {
00387 #ifndef _WIN32_WCE
00388     waitUntilSocketIsReadable(fEnv, (int)fileno(fFid));
00389 #endif
00390     return fread(buf, 1, numChars, fFid);
00391   }
00392 }

MP3FrameParams& MP3StreamState::fr (  )  [inline, private]

Definition at line 68 of file MP3StreamState.hh.

References fCurrentFrame.

Referenced by checkForXingHeader(), currentFramePlayTime(), findNextFrame(), findNextHeader(), getAttributes(), and readFrame().

00068 {return fCurrentFrame;}

MP3FrameParams const& MP3StreamState::fr (  )  const [inline, private]

Definition at line 69 of file MP3StreamState.hh.

References fCurrentFrame.

00069 {return fCurrentFrame;}

struct timeval MP3StreamState::currentFramePlayTime (  )  const [read, private]

Definition at line 67 of file MP3StreamState.cpp.

References fr(), MP3FrameParams::isMPEG2, MILLION, and MP3FrameParams::samplingFreq.

Referenced by filePlayTime(), findNextHeader(), and readFrame().

00067                                                           {
00068   unsigned const numSamples = 1152;
00069   unsigned const freq = fr().samplingFreq*(1 + fr().isMPEG2);
00070 
00071   // result is numSamples/freq
00072   unsigned const uSeconds
00073     = ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer
00074 
00075   struct timeval result;
00076   result.tv_sec = uSeconds/MILLION;
00077   result.tv_usec = uSeconds%MILLION;
00078   return result;
00079 }

Boolean MP3StreamState::findNextFrame (  )  [private]

Definition at line 195 of file MP3StreamState.cpp.

References False, MP3FrameParams::firstHdr, fr(), frameSize, MP3FrameParams::hdr, HDRCMPMASK, MP3FrameParams::oldHdr, readFromStream(), MP3FrameParams::setBytePointer(), MP3FrameParams::setParamsFromHeader(), and True.

Referenced by findNextHeader().

00195                                       {
00196   unsigned char hbuf[8];
00197   unsigned l; int i;
00198   int attempt = 0;
00199 
00200  read_again:
00201   if (readFromStream(hbuf, 4) != 4) return False;
00202 
00203   fr().hdr =  ((unsigned long) hbuf[0] << 24)
00204             | ((unsigned long) hbuf[1] << 16)
00205             | ((unsigned long) hbuf[2] << 8)
00206             | (unsigned long) hbuf[3];
00207 
00208 #ifdef DEBUG_PARSE
00209   fprintf(stderr, "fr().hdr: 0x%08x\n", fr().hdr);
00210 #endif
00211   if (fr().oldHdr != fr().hdr || !fr().oldHdr) {
00212     i = 0;
00213   init_resync:
00214 #ifdef DEBUG_PARSE
00215     fprintf(stderr, "init_resync: fr().hdr: 0x%08x\n", fr().hdr);
00216 #endif
00217     if (   (fr().hdr & 0xffe00000) != 0xffe00000
00218         || (fr().hdr & 0x00060000) == 0 // undefined 'layer' field
00219         || (fr().hdr & 0x0000F000) == 0 // 'free format' bitrate index
00220         || (fr().hdr & 0x0000F000) == 0x0000F000 // undefined bitrate index
00221         || (fr().hdr & 0x00000C00) == 0x00000C00 // undefined frequency index
00222         || (fr().hdr & 0x00000003) != 0x00000000 // 'emphasis' field unexpectedly set
00223        ) {
00224       /* RSF: Do the following test even if we're not at the
00225          start of the file, in case we have two or more
00226          separate MP3 files cat'ed together:
00227       */
00228       /* Check for RIFF hdr */
00229       if (fr().hdr == ('R'<<24)+('I'<<16)+('F'<<8)+'F') {
00230         unsigned char buf[70 /*was: 40*/];
00231 #ifdef DEBUG_ERRORS
00232         fprintf(stderr,"Skipped RIFF header\n");
00233 #endif
00234         readFromStream(buf, 66); /* already read 4 */
00235         goto read_again;
00236       }
00237       /* Check for ID3 hdr */
00238       if ((fr().hdr&0xFFFFFF00) == ('I'<<24)+('D'<<16)+('3'<<8)) {
00239         unsigned tagSize, bytesToSkip;
00240         unsigned char buf[1000];
00241         readFromStream(buf, 6); /* already read 4 */
00242         tagSize = ((buf[2]&0x7F)<<21) + ((buf[3]&0x7F)<<14) + ((buf[4]&0x7F)<<7) + (buf[5]&0x7F);
00243         bytesToSkip = tagSize;
00244         while (bytesToSkip > 0) {
00245           unsigned bytesToRead = sizeof buf;
00246           if (bytesToRead > bytesToSkip) {
00247             bytesToRead = bytesToSkip;
00248           }
00249           readFromStream(buf, bytesToRead);
00250           bytesToSkip -= bytesToRead;
00251         }
00252 #ifdef DEBUG_ERRORS
00253         fprintf(stderr,"Skipped %d-byte ID3 header\n", tagSize);
00254 #endif
00255         goto read_again;
00256       }
00257       /* give up after 20,000 bytes */
00258       if (i++ < 20000/*4096*//*1024*/) {
00259         memmove (&hbuf[0], &hbuf[1], 3);
00260         if (readFromStream(hbuf+3,1) != 1) {
00261           return False;
00262         }
00263         fr().hdr <<= 8;
00264         fr().hdr |= hbuf[3];
00265         fr().hdr &= 0xffffffff;
00266 #ifdef DEBUG_PARSE
00267         fprintf(stderr, "calling init_resync %d\n", i);
00268 #endif
00269         goto init_resync;
00270       }
00271 #ifdef DEBUG_ERRORS
00272       fprintf(stderr,"Giving up searching valid MPEG header\n");
00273 #endif
00274       return False;
00275 
00276 #ifdef DEBUG_ERRORS
00277       fprintf(stderr,"Illegal Audio-MPEG-Header 0x%08lx at offset 0x%lx.\n",
00278               fr().hdr,tell_stream(str)-4);
00279 #endif
00280       /* Read more bytes until we find something that looks
00281          reasonably like a valid header.  This is not a
00282          perfect strategy, but it should get us back on the
00283          track within a short time (and hopefully without
00284          too much distortion in the audio output).  */
00285       do {
00286         attempt++;
00287         memmove (&hbuf[0], &hbuf[1], 7);
00288         if (readFromStream(&hbuf[3],1) != 1) {
00289           return False;
00290         }
00291 
00292         /* This is faster than combining fr().hdr from scratch */
00293         fr().hdr = ((fr().hdr << 8) | hbuf[3]) & 0xffffffff;
00294 
00295         if (!fr().oldHdr)
00296           goto init_resync;       /* "considered harmful", eh? */
00297 
00298       } while ((fr().hdr & HDRCMPMASK) != (fr().oldHdr & HDRCMPMASK)
00299                && (fr().hdr & HDRCMPMASK) != (fr().firstHdr & HDRCMPMASK));
00300 #ifdef DEBUG_ERRORS
00301       fprintf (stderr, "Skipped %d bytes in input.\n", attempt);
00302 #endif
00303     }
00304     if (!fr().firstHdr) {
00305       fr().firstHdr = fr().hdr;
00306     }
00307 
00308     fr().setParamsFromHeader();
00309     fr().setBytePointer(fr().frameBytes, fr().frameSize);
00310 
00311     fr().oldHdr = fr().hdr;
00312 
00313     if (fr().isFreeFormat) {
00314 #ifdef DEBUG_ERRORS
00315       fprintf(stderr,"Free format not supported.\n");
00316 #endif
00317       return False;
00318     }
00319 
00320 #ifdef MP3_ONLY
00321     if (fr().layer != 3) {
00322 #ifdef DEBUG_ERRORS
00323       fprintf(stderr, "MPEG layer %d is not supported!\n", fr().layer);
00324 #endif
00325       return False;
00326     }
00327 #endif
00328   }
00329 
00330   if ((l = readFromStream(fr().frameBytes, fr().frameSize))
00331       != fr().frameSize) {
00332     if (l == 0) return False;
00333     memset(fr().frameBytes+1, 0, fr().frameSize-1);
00334   }
00335 
00336   return True;
00337 }


Field Documentation

UsageEnvironment& MP3StreamState::fEnv [private]

Definition at line 76 of file MP3StreamState.hh.

Referenced by readFromStream().

FILE* MP3StreamState::fFid [private]

Definition at line 77 of file MP3StreamState.hh.

Referenced by assignStream(), readFromStream(), seekWithinFile(), and ~MP3StreamState().

Boolean MP3StreamState::fFidIsReallyASocket [private]

Definition at line 78 of file MP3StreamState.hh.

Referenced by assignStream(), readFromStream(), seekWithinFile(), and ~MP3StreamState().

unsigned MP3StreamState::fFileSize [private]

Definition at line 79 of file MP3StreamState.hh.

Referenced by assignStream(), checkForXingHeader(), filePlayTime(), fileSize(), and getByteNumberFromPositionFraction().

unsigned MP3StreamState::fNumFramesInFile [private]

Definition at line 80 of file MP3StreamState.hh.

Referenced by assignStream(), checkForXingHeader(), and filePlayTime().

unsigned MP3StreamState::fPresentationTimeScale [private]

Definition at line 81 of file MP3StreamState.hh.

Referenced by findNextHeader(), and setPresentationTimeScale().

Boolean MP3StreamState::fIsVBR [private]

Definition at line 83 of file MP3StreamState.hh.

Referenced by assignStream(), checkForXingHeader(), and getAttributes().

Boolean MP3StreamState::fHasXingTOC [private]

Definition at line 83 of file MP3StreamState.hh.

Referenced by assignStream(), checkForXingHeader(), and getByteNumberFromPositionFraction().

u_int8_t MP3StreamState::fXingTOC[XING_TOC_LENGTH] [private]

Definition at line 84 of file MP3StreamState.hh.

Referenced by checkForXingHeader(), and getByteNumberFromPositionFraction().

MP3FrameParams MP3StreamState::fCurrentFrame [private]

Definition at line 86 of file MP3StreamState.hh.

Referenced by filePlayTime(), and fr().

struct timeval MP3StreamState::fNextFramePresentationTime [read, private]

Definition at line 87 of file MP3StreamState.hh.

Referenced by assignStream(), and findNextHeader().


The documentation for this class was generated from the following files:
Generated on Tue Mar 25 14:39:57 2014 for live by  doxygen 1.5.2