liveMedia/MP3ADUinterleaving.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-2014 Live Networks, Inc.  All rights reserved.
00018 // Interleaving of MP3 ADUs
00019 // Implementation
00020 
00021 #include "MP3ADUinterleaving.hh"
00022 #include "MP3ADUdescriptor.hh"
00023 
00024 #include <string.h>
00025 
00026 #ifdef TEST_LOSS
00027 #include "GroupsockHelper.hh"
00028 #endif
00029 
00031 
00032 Interleaving::Interleaving(unsigned cycleSize,
00033                            unsigned char const* cycleArray)
00034   : fCycleSize(cycleSize) {
00035   for (unsigned i = 0; i < fCycleSize; ++i) {
00036     fInverseCycle[cycleArray[i]] = i;
00037   }
00038 }
00039 
00040 Interleaving::~Interleaving() {
00041 }
00042 
00044 
00045 MP3ADUinterleaverBase::MP3ADUinterleaverBase(UsageEnvironment& env,
00046                                              FramedSource* inputSource)
00047   : FramedFilter(env, inputSource) {
00048 }
00049 MP3ADUinterleaverBase::~MP3ADUinterleaverBase() {
00050 }
00051 
00052 FramedSource* MP3ADUinterleaverBase::getInputSource(UsageEnvironment& env,
00053                                                     char const* inputSourceName) {
00054   FramedSource* inputSource;
00055   if (!FramedSource::lookupByName(env, inputSourceName, inputSource))
00056     return NULL;
00057 
00058   if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) {
00059     env.setResultMsg(inputSourceName, " is not an MP3 ADU source");
00060     return NULL;
00061   }
00062 
00063   return inputSource;
00064 }
00065 
00066 void MP3ADUinterleaverBase::afterGettingFrame(void* clientData,
00067                                               unsigned numBytesRead,
00068                                               unsigned /*numTruncatedBytes*/,
00069                                               struct timeval presentationTime,
00070                                               unsigned durationInMicroseconds) {
00071   MP3ADUinterleaverBase* interleaverBase = (MP3ADUinterleaverBase*)clientData;
00072   // Finish up after reading:
00073   interleaverBase->afterGettingFrame(numBytesRead,
00074                                      presentationTime, durationInMicroseconds);
00075 
00076   // Then, continue to deliver an outgoing frame:
00077   interleaverBase->doGetNextFrame();
00078 }
00079 
00080 
00082 
00083 class InterleavingFrames {
00084 public:
00085   InterleavingFrames(unsigned maxCycleSize);
00086   virtual ~InterleavingFrames();
00087 
00088   Boolean haveReleaseableFrame();
00089   void getIncomingFrameParams(unsigned char index,
00090                               unsigned char*& dataPtr,
00091                               unsigned& bytesAvailable);
00092   void getReleasingFrameParams(unsigned char index,
00093                                unsigned char*& dataPtr,
00094                                unsigned& bytesInUse,
00095                                struct timeval& presentationTime,
00096                                unsigned& durationInMicroseconds);
00097   void setFrameParams(unsigned char index,
00098                       unsigned char icc, unsigned char ii,
00099                       unsigned frameSize, struct timeval presentationTime,
00100                       unsigned durationInMicroseconds);
00101   unsigned nextIndexToRelease() {return fNextIndexToRelease;}
00102   void releaseNext();
00103 
00104 private:
00105   unsigned fMaxCycleSize;
00106   unsigned fNextIndexToRelease;
00107   class InterleavingFrameDescriptor* fDescriptors;
00108 };
00109 
00111 
00112 
00113 MP3ADUinterleaver::MP3ADUinterleaver(UsageEnvironment& env,
00114                                      Interleaving const& interleaving,
00115                                      FramedSource* inputSource)
00116   : MP3ADUinterleaverBase(env, inputSource),
00117     fInterleaving(interleaving),
00118     fFrames(new InterleavingFrames(interleaving.cycleSize())),
00119     fII(0), fICC(0) {
00120 }
00121 
00122 MP3ADUinterleaver::~MP3ADUinterleaver() {
00123   delete fFrames;
00124 }
00125 
00126 MP3ADUinterleaver* MP3ADUinterleaver::createNew(UsageEnvironment& env,
00127                                                 Interleaving const& interleaving,
00128                                                 FramedSource* inputSource) {
00129   return new MP3ADUinterleaver(env, interleaving, inputSource);
00130 }
00131 
00132 void MP3ADUinterleaver::doGetNextFrame() {
00133   // If there's a frame immediately available, deliver it, otherwise get new
00134   // frames from the source until one's available:
00135   if (fFrames->haveReleaseableFrame()) {
00136     releaseOutgoingFrame();
00137 
00138     // Call our own 'after getting' function.  Because we're not a 'leaf'
00139     // source, we can call this directly, without risking infinite recursion.
00140     afterGetting(this);
00141   } else {
00142     fPositionOfNextIncomingFrame = fInterleaving.lookupInverseCycle(fII);
00143     unsigned char* dataPtr;
00144     unsigned bytesAvailable;
00145     fFrames->getIncomingFrameParams(fPositionOfNextIncomingFrame,
00146                                     dataPtr, bytesAvailable);
00147 
00148     // Read the next incoming frame (asynchronously)
00149     fInputSource->getNextFrame(dataPtr, bytesAvailable,
00150                                &MP3ADUinterleaverBase::afterGettingFrame, this,
00151                                handleClosure, this);
00152   }
00153 }
00154 
00155 void MP3ADUinterleaver::releaseOutgoingFrame() {
00156   unsigned char* fromPtr;
00157   fFrames->getReleasingFrameParams(fFrames->nextIndexToRelease(),
00158                                    fromPtr, fFrameSize,
00159                                    fPresentationTime, fDurationInMicroseconds);
00160 
00161   if (fFrameSize > fMaxSize) {
00162     fNumTruncatedBytes = fFrameSize - fMaxSize;
00163     fFrameSize = fMaxSize;
00164   }
00165   memmove(fTo, fromPtr, fFrameSize);
00166 
00167   fFrames->releaseNext();
00168 }
00169 
00170 void MP3ADUinterleaver::afterGettingFrame(unsigned numBytesRead,
00171                                           struct timeval presentationTime,
00172                                           unsigned durationInMicroseconds) {
00173   // Set the (icc,ii) and frame size of the newly-read frame:
00174   fFrames->setFrameParams(fPositionOfNextIncomingFrame,
00175                           fICC, fII, numBytesRead,
00176                           presentationTime, durationInMicroseconds);
00177 
00178   // Prepare our counters for the next frame:
00179   if (++fII == fInterleaving.cycleSize()) {
00180     fII = 0;
00181     fICC = (fICC+1)%8;
00182   }
00183 }
00184 
00186 
00187 class DeinterleavingFrames {
00188 public:
00189   DeinterleavingFrames();
00190   virtual ~DeinterleavingFrames();
00191 
00192   Boolean haveReleaseableFrame();
00193   void getIncomingFrameParams(unsigned char*& dataPtr,
00194                               unsigned& bytesAvailable);
00195   void getIncomingFrameParamsAfter(unsigned frameSize,
00196                                    struct timeval presentationTime,
00197                                    unsigned durationInMicroseconds,
00198                                    unsigned char& icc, unsigned char& ii);
00199   void getReleasingFrameParams(unsigned char*& dataPtr,
00200                                unsigned& bytesInUse,
00201                                struct timeval& presentationTime,
00202                                unsigned& durationInMicroseconds);
00203   void moveIncomingFrameIntoPlace();
00204   void releaseNext();
00205   void startNewCycle();
00206 
00207 private:
00208   unsigned fNextIndexToRelease;
00209   Boolean fHaveEndedCycle;
00210   unsigned fIIlastSeen;
00211   unsigned fMinIndexSeen, fMaxIndexSeen; // actually, max+1
00212   class DeinterleavingFrameDescriptor* fDescriptors;
00213 };
00214 
00216 
00217 MP3ADUdeinterleaver::MP3ADUdeinterleaver(UsageEnvironment& env,
00218                                          FramedSource* inputSource)
00219   : MP3ADUinterleaverBase(env, inputSource),
00220     fFrames(new DeinterleavingFrames),
00221     fIIlastSeen(~0), fICClastSeen(~0) {
00222 }
00223 
00224 MP3ADUdeinterleaver::~MP3ADUdeinterleaver() {
00225   delete fFrames;
00226 }
00227 
00228 MP3ADUdeinterleaver* MP3ADUdeinterleaver::createNew(UsageEnvironment& env,
00229                                                     FramedSource* inputSource) {
00230   return new MP3ADUdeinterleaver(env, inputSource);
00231 }
00232 
00233 void MP3ADUdeinterleaver::doGetNextFrame() {
00234   // If there's a frame immediately available, deliver it, otherwise get new
00235   // frames from the source until one's available:
00236   if (fFrames->haveReleaseableFrame()) {
00237     releaseOutgoingFrame();
00238 
00239     // Call our own 'after getting' function.  Because we're not a 'leaf'
00240     // source, we can call this directly, without risking infinite recursion.
00241     afterGetting(this);
00242   } else {
00243 #ifdef TEST_LOSS
00244   NOTE: This code no longer works, because it uses synchronous reads,
00245   which are no longer supported.
00246     static unsigned const framesPerPacket = 3;
00247     static unsigned const frameCount = 0;
00248     static Boolean packetIsLost;
00249     while (1) {
00250       unsigned packetCount = frameCount/framesPerPacket;
00251       if ((frameCount++)%framesPerPacket == 0) {
00252         packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
00253       }
00254 
00255       if (packetIsLost) {
00256         // Read and discard the next input frame (that would be part of
00257         // a lost packet):
00258         unsigned char dummyBuf[2000];
00259         unsigned numBytesRead;
00260         struct timeval presentationTime;
00261         // (this works only if the source can be read synchronously)
00262         fInputSource->syncGetNextFrame(dummyBuf, sizeof dummyBuf,
00263                                        numBytesRead, presentationTime);
00264       } else {
00265         break; // from while (1)
00266       }
00267     }
00268 #endif
00269     unsigned char* dataPtr;
00270     unsigned bytesAvailable;
00271     fFrames->getIncomingFrameParams(dataPtr, bytesAvailable);
00272 
00273     // Read the next incoming frame (asynchronously)
00274     fInputSource->getNextFrame(dataPtr, bytesAvailable,
00275                                &MP3ADUinterleaverBase::afterGettingFrame, this,
00276                                handleClosure, this);
00277   }
00278 }
00279 
00280 void MP3ADUdeinterleaver::afterGettingFrame(unsigned numBytesRead,
00281                                             struct timeval presentationTime,
00282                                             unsigned durationInMicroseconds) {
00283   // Get the (icc,ii) and set the frame size of the newly-read frame:
00284   unsigned char icc, ii;
00285   fFrames->getIncomingFrameParamsAfter(numBytesRead,
00286                                        presentationTime, durationInMicroseconds,
00287                                        icc, ii);
00288 
00289   // Compare these to the values we saw last:
00290   if (icc != fICClastSeen || ii == fIIlastSeen) {
00291     // We've started a new interleave cycle
00292     // (or interleaving was not used).  Release all
00293     // pending ADU frames to the ADU->MP3 conversion step:
00294     fFrames->startNewCycle();
00295   } else {
00296     // We're still in the same cycle as before.
00297     // Move the newly-read frame into place, so it can be used:
00298     fFrames->moveIncomingFrameIntoPlace();
00299   }
00300 
00301   fICClastSeen = icc;
00302   fIIlastSeen = ii;
00303 }
00304 
00305 void MP3ADUdeinterleaver::releaseOutgoingFrame() {
00306   unsigned char* fromPtr;
00307   fFrames->getReleasingFrameParams(fromPtr, fFrameSize,
00308                                    fPresentationTime, fDurationInMicroseconds);
00309 
00310   if (fFrameSize > fMaxSize) {
00311     fNumTruncatedBytes = fFrameSize - fMaxSize;
00312     fFrameSize = fMaxSize;
00313   }
00314   memmove(fTo, fromPtr, fFrameSize);
00315 
00316   fFrames->releaseNext();
00317 }
00318 
00320 
00321 #define MAX_FRAME_SIZE 2000 /* conservatively high */
00322 
00323 class InterleavingFrameDescriptor {
00324 public:
00325   InterleavingFrameDescriptor() {frameDataSize = 0;}
00326 
00327   unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr
00328   struct timeval presentationTime;
00329   unsigned durationInMicroseconds;
00330   unsigned char frameData[MAX_FRAME_SIZE]; // ditto
00331 };
00332 
00333 InterleavingFrames::InterleavingFrames(unsigned maxCycleSize)
00334   : fMaxCycleSize(maxCycleSize), fNextIndexToRelease(0),
00335     fDescriptors(new InterleavingFrameDescriptor[maxCycleSize]) {
00336 }
00337 InterleavingFrames::~InterleavingFrames() {
00338   delete[] fDescriptors;
00339 }
00340 
00341 Boolean InterleavingFrames::haveReleaseableFrame() {
00342   return fDescriptors[fNextIndexToRelease].frameDataSize > 0;
00343 }
00344 
00345 void InterleavingFrames::getIncomingFrameParams(unsigned char index,
00346                                                 unsigned char*& dataPtr,
00347                                                 unsigned& bytesAvailable) {
00348   InterleavingFrameDescriptor& desc = fDescriptors[index];
00349   dataPtr = &desc.frameData[0];
00350   bytesAvailable = MAX_FRAME_SIZE;
00351 }
00352 
00353 void InterleavingFrames::getReleasingFrameParams(unsigned char index,
00354                                                  unsigned char*& dataPtr,
00355                                                  unsigned& bytesInUse,
00356                                                  struct timeval& presentationTime,
00357                                                  unsigned& durationInMicroseconds) {
00358   InterleavingFrameDescriptor& desc = fDescriptors[index];
00359   dataPtr = &desc.frameData[0];
00360   bytesInUse = desc.frameDataSize;
00361   presentationTime = desc.presentationTime;
00362   durationInMicroseconds = desc.durationInMicroseconds;
00363 }
00364 
00365 void InterleavingFrames::setFrameParams(unsigned char index,
00366                                         unsigned char icc,
00367                                         unsigned char ii,
00368                                         unsigned frameSize,
00369                                         struct timeval presentationTime,
00370                                         unsigned durationInMicroseconds) {
00371   InterleavingFrameDescriptor& desc = fDescriptors[index];
00372   desc.frameDataSize = frameSize;
00373   desc.presentationTime = presentationTime;
00374   desc.durationInMicroseconds = durationInMicroseconds;
00375 
00376   // Advance over the ADU descriptor, to get to the MPEG 'syncword':
00377   unsigned char* ptr = &desc.frameData[0];
00378   (void)ADUdescriptor::getRemainingFrameSize(ptr);
00379 
00380   // Replace the next 11 bits with (ii,icc):
00381   *ptr++ = ii;
00382   *ptr &=~ 0xE0;
00383   *ptr |= (icc<<5);
00384 }
00385 
00386 void InterleavingFrames::releaseNext() {
00387   fDescriptors[fNextIndexToRelease].frameDataSize = 0;
00388   fNextIndexToRelease = (fNextIndexToRelease+1)%fMaxCycleSize;
00389 }
00390 
00392 
00393 class DeinterleavingFrameDescriptor {
00394 public:
00395   DeinterleavingFrameDescriptor() {frameDataSize = 0; frameData = NULL;}
00396   virtual ~DeinterleavingFrameDescriptor() {delete[] frameData;}
00397 
00398   unsigned frameDataSize; // includes ADU descriptor and (modified) MPEG hdr
00399   struct timeval presentationTime;
00400   unsigned durationInMicroseconds;
00401   unsigned char* frameData;
00402 };
00403 
00404 DeinterleavingFrames::DeinterleavingFrames()
00405   : fNextIndexToRelease(0), fHaveEndedCycle(False),
00406     fMinIndexSeen(MAX_CYCLE_SIZE), fMaxIndexSeen(0),
00407     fDescriptors(new DeinterleavingFrameDescriptor[MAX_CYCLE_SIZE+1]) {
00408 }
00409 DeinterleavingFrames::~DeinterleavingFrames() {
00410   delete[] fDescriptors;
00411 }
00412 
00413 Boolean DeinterleavingFrames::haveReleaseableFrame() {
00414   if (!fHaveEndedCycle) {
00415     // Check just the next frame in the sequence
00416     return fDescriptors[fNextIndexToRelease].frameDataSize > 0;
00417   } else {
00418     // We've just ended a cycle, so we can skip over frames that didn't
00419     // get filled in (due to packet loss):
00420     if (fNextIndexToRelease < fMinIndexSeen) {
00421       fNextIndexToRelease = fMinIndexSeen;
00422     }
00423     while (fNextIndexToRelease < fMaxIndexSeen
00424            && fDescriptors[fNextIndexToRelease].frameDataSize == 0) {
00425       ++fNextIndexToRelease;
00426     }
00427     if (fNextIndexToRelease >= fMaxIndexSeen) {
00428       // No more frames are available from the cycle that we just ended, so
00429       // clear out all previously stored frames, then make available
00430       // the last-read frame, and return false for now:
00431       for (unsigned i = fMinIndexSeen; i < fMaxIndexSeen; ++i) {
00432         fDescriptors[i].frameDataSize = 0;
00433       }
00434 
00435       fMinIndexSeen = MAX_CYCLE_SIZE; fMaxIndexSeen = 0;
00436       moveIncomingFrameIntoPlace();
00437 
00438       fHaveEndedCycle = False;
00439       fNextIndexToRelease = 0;
00440       return False;
00441     }
00442 
00443     return True;
00444   }
00445 }
00446 
00447 void DeinterleavingFrames::getIncomingFrameParams(unsigned char*& dataPtr,
00448                                                   unsigned& bytesAvailable) {
00449   // Use fDescriptors[MAX_CYCLE_SIZE] to store the incoming frame,
00450   // prior to figuring out its real position:
00451   DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE];
00452   if (desc.frameData == NULL) {
00453     // There's no buffer yet, so allocate a new one:
00454     desc.frameData = new unsigned char[MAX_FRAME_SIZE];
00455   }
00456   dataPtr = desc.frameData;
00457   bytesAvailable = MAX_FRAME_SIZE;
00458 }
00459 
00460 void DeinterleavingFrames
00461 ::getIncomingFrameParamsAfter(unsigned frameSize,
00462                               struct timeval presentationTime,
00463                               unsigned durationInMicroseconds,
00464                               unsigned char& icc, unsigned char& ii) {
00465   DeinterleavingFrameDescriptor& desc = fDescriptors[MAX_CYCLE_SIZE];
00466   desc.frameDataSize = frameSize;
00467   desc.presentationTime = presentationTime;
00468   desc.durationInMicroseconds = durationInMicroseconds;
00469 
00470   // Advance over the ADU descriptor, to get to the MPEG 'syncword':
00471   unsigned char* ptr = desc.frameData;
00472   (void)ADUdescriptor::getRemainingFrameSize(ptr);
00473 
00474   // Read the next 11 bits into (ii,icc), and replace them with all-1s:
00475   fIIlastSeen = ii = *ptr; *ptr++ = 0xFF;
00476   icc = (*ptr&0xE0)>>5; *ptr |= 0xE0;
00477 }
00478 
00479 void DeinterleavingFrames::getReleasingFrameParams(unsigned char*& dataPtr,
00480                                                    unsigned& bytesInUse,
00481                                                    struct timeval& presentationTime,
00482                                                    unsigned& durationInMicroseconds) {
00483   DeinterleavingFrameDescriptor& desc = fDescriptors[fNextIndexToRelease];
00484   dataPtr = desc.frameData;
00485   bytesInUse = desc.frameDataSize;
00486   presentationTime = desc.presentationTime;
00487   durationInMicroseconds = desc.durationInMicroseconds;
00488 }
00489 
00490 void DeinterleavingFrames::moveIncomingFrameIntoPlace() {
00491   DeinterleavingFrameDescriptor& fromDesc = fDescriptors[MAX_CYCLE_SIZE];
00492   DeinterleavingFrameDescriptor& toDesc = fDescriptors[fIIlastSeen];
00493 
00494   toDesc.frameDataSize = fromDesc.frameDataSize;
00495   toDesc.presentationTime = fromDesc.presentationTime;
00496 
00497   // Move the data pointer into place by swapping the data pointers:
00498   unsigned char* tmp = toDesc.frameData;
00499   toDesc.frameData = fromDesc.frameData;
00500   fromDesc.frameData = tmp;
00501 
00502   if (fIIlastSeen < fMinIndexSeen) {
00503     fMinIndexSeen = fIIlastSeen;
00504   }
00505   if (fIIlastSeen + 1 > fMaxIndexSeen) {
00506     fMaxIndexSeen = fIIlastSeen + 1;
00507   }
00508 }
00509 
00510 void DeinterleavingFrames::releaseNext() {
00511   fDescriptors[fNextIndexToRelease].frameDataSize = 0;
00512   fNextIndexToRelease = (fNextIndexToRelease+1)%MAX_CYCLE_SIZE;
00513 }
00514 
00515 void DeinterleavingFrames::startNewCycle() {
00516   fHaveEndedCycle = True;
00517 }

Generated on Tue Mar 25 14:35:35 2014 for live by  doxygen 1.5.2