liveMedia/MPEG1or2AudioStreamFramer.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2013 Live Networks, Inc.  All rights reserved.
00018 // A filter that breaks up an MPEG (1,2) audio elementary stream into frames
00019 // Implementation
00020 
00021 #include "MPEG1or2AudioStreamFramer.hh"
00022 #include "StreamParser.hh"
00023 #include "MP3Internals.hh"
00024 #include <GroupsockHelper.hh>
00025 
00027 
00028 class MPEG1or2AudioStreamParser: public StreamParser {
00029 public:
00030   MPEG1or2AudioStreamParser(MPEG1or2AudioStreamFramer* usingSource,
00031                         FramedSource* inputSource);
00032   virtual ~MPEG1or2AudioStreamParser();
00033 
00034 public:
00035   unsigned parse(unsigned& numTruncatedBytes);
00036       // returns the size of the frame that was acquired, or 0 if none was
00037 
00038   void registerReadInterest(unsigned char* to, unsigned maxSize);
00039 
00040   MP3FrameParams const& currentFrame() const { return fCurrentFrame; }
00041 
00042 private:
00043   unsigned char* fTo;
00044   unsigned fMaxSize;
00045 
00046   // Parameters of the most recently read frame:
00047   MP3FrameParams fCurrentFrame; // also works for layer I or II
00048 };
00049 
00050 
00052 
00053 MPEG1or2AudioStreamFramer
00054 ::MPEG1or2AudioStreamFramer(UsageEnvironment& env, FramedSource* inputSource,
00055                             Boolean syncWithInputSource)
00056   : FramedFilter(env, inputSource),
00057     fSyncWithInputSource(syncWithInputSource) {
00058   reset();
00059 
00060   fParser = new MPEG1or2AudioStreamParser(this, inputSource);
00061 }
00062 
00063 MPEG1or2AudioStreamFramer::~MPEG1or2AudioStreamFramer() {
00064   delete fParser;
00065 }
00066 
00067 MPEG1or2AudioStreamFramer*
00068 MPEG1or2AudioStreamFramer::createNew(UsageEnvironment& env,
00069                                      FramedSource* inputSource,
00070                                      Boolean syncWithInputSource) {
00071   // Need to add source type checking here???  #####
00072   return new MPEG1or2AudioStreamFramer(env, inputSource, syncWithInputSource);
00073 }
00074 
00075 void MPEG1or2AudioStreamFramer::flushInput() {
00076   reset();
00077   fParser->flushInput();
00078 }
00079 
00080 void MPEG1or2AudioStreamFramer::reset() {
00081   // Use the current wallclock time as the initial 'presentation time':
00082   struct timeval timeNow;
00083   gettimeofday(&timeNow, NULL);
00084   resetPresentationTime(timeNow);
00085 }
00086 
00087 void MPEG1or2AudioStreamFramer
00088 ::resetPresentationTime(struct timeval newPresentationTime) {
00089   fNextFramePresentationTime = newPresentationTime;
00090 }
00091 
00092 void MPEG1or2AudioStreamFramer::doGetNextFrame() {
00093   fParser->registerReadInterest(fTo, fMaxSize);
00094   continueReadProcessing();
00095 }
00096 
00097 #define MILLION 1000000
00098 
00099 static unsigned const numSamplesByLayer[4] = {0, 384, 1152, 1152};
00100 
00101 struct timeval MPEG1or2AudioStreamFramer::currentFramePlayTime() const {
00102   MP3FrameParams const& fr = fParser->currentFrame();
00103   unsigned const numSamples = numSamplesByLayer[fr.layer];
00104 
00105   struct timeval result;
00106   unsigned const freq = fr.samplingFreq*(1 + fr.isMPEG2);
00107   if (freq == 0) {
00108     result.tv_sec = 0;
00109     result.tv_usec = 0;
00110     return result;
00111   }
00112 
00113   // result is numSamples/freq
00114   unsigned const uSeconds
00115     = ((numSamples*2*MILLION)/freq + 1)/2; // rounds to nearest integer
00116 
00117   result.tv_sec = uSeconds/MILLION;
00118   result.tv_usec = uSeconds%MILLION;
00119   return result;
00120 }
00121 
00122 void MPEG1or2AudioStreamFramer
00123 ::continueReadProcessing(void* clientData,
00124                          unsigned char* /*ptr*/, unsigned /*size*/,
00125                          struct timeval presentationTime) {
00126   MPEG1or2AudioStreamFramer* framer = (MPEG1or2AudioStreamFramer*)clientData;
00127   if (framer->fSyncWithInputSource) {
00128     framer->resetPresentationTime(presentationTime);
00129   }
00130   framer->continueReadProcessing();
00131 }
00132 
00133 void MPEG1or2AudioStreamFramer::continueReadProcessing() {
00134   unsigned acquiredFrameSize = fParser->parse(fNumTruncatedBytes);
00135   if (acquiredFrameSize > 0) {
00136     // We were able to acquire a frame from the input.
00137     // It has already been copied to the reader's space.
00138     fFrameSize = acquiredFrameSize;
00139 
00140     // Also set the presentation time, and increment it for next time,
00141     // based on the length of this frame:
00142     fPresentationTime = fNextFramePresentationTime;
00143     struct timeval framePlayTime = currentFramePlayTime();
00144     fDurationInMicroseconds = framePlayTime.tv_sec*MILLION + framePlayTime.tv_usec;
00145     fNextFramePresentationTime.tv_usec += framePlayTime.tv_usec;
00146     fNextFramePresentationTime.tv_sec
00147       += framePlayTime.tv_sec + fNextFramePresentationTime.tv_usec/MILLION;
00148     fNextFramePresentationTime.tv_usec %= MILLION;
00149 
00150     // Call our own 'after getting' function.  Because we're not a 'leaf'
00151     // source, we can call this directly, without risking infinite recursion.
00152     afterGetting(this);
00153   } else {
00154     // We were unable to parse a complete frame from the input, because:
00155     // - we had to read more data from the source stream, or
00156     // - the source stream has ended.
00157   }
00158 }
00159 
00160 
00162 
00163 MPEG1or2AudioStreamParser
00164 ::MPEG1or2AudioStreamParser(MPEG1or2AudioStreamFramer* usingSource,
00165                         FramedSource* inputSource)
00166   : StreamParser(inputSource, FramedSource::handleClosure, usingSource,
00167                  &MPEG1or2AudioStreamFramer::continueReadProcessing, usingSource) {
00168 }
00169 
00170 MPEG1or2AudioStreamParser::~MPEG1or2AudioStreamParser() {
00171 }
00172 
00173 void MPEG1or2AudioStreamParser::registerReadInterest(unsigned char* to,
00174                                                  unsigned maxSize) {
00175   fTo = to;
00176   fMaxSize = maxSize;
00177 }
00178 
00179 unsigned MPEG1or2AudioStreamParser::parse(unsigned& numTruncatedBytes) {
00180   try {
00181     saveParserState();
00182 
00183     // We expect a MPEG audio header (first 11 bits set to 1) at the start:
00184     while (((fCurrentFrame.hdr = test4Bytes())&0xFFE00000) != 0xFFE00000) {
00185       skipBytes(1);
00186       saveParserState();
00187     }
00188 
00189     fCurrentFrame.setParamsFromHeader();
00190 
00191     // Copy the frame to the requested destination:
00192     unsigned frameSize = fCurrentFrame.frameSize + 4; // include header
00193     if (frameSize > fMaxSize) {
00194       numTruncatedBytes = frameSize - fMaxSize;
00195       frameSize = fMaxSize;
00196     } else {
00197       numTruncatedBytes = 0;
00198     }
00199 
00200     getBytes(fTo, frameSize);
00201     skipBytes(numTruncatedBytes);
00202 
00203     return frameSize;
00204   } catch (int /*e*/) {
00205 #ifdef DEBUG
00206     fprintf(stderr, "MPEG1or2AudioStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");
00207 #endif
00208     return 0;  // the parsing got interrupted
00209   }
00210 }

Generated on Mon Apr 29 13:28:02 2013 for live by  doxygen 1.5.2