liveMedia/MP3ADU.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 // 'ADU' MP3 streams (for improved loss-tolerance)
00019 // Implementation
00020 
00021 #include "MP3ADU.hh"
00022 #include "MP3ADUdescriptor.hh"
00023 #include "MP3Internals.hh"
00024 #include <string.h>
00025 
00026 #ifdef TEST_LOSS
00027 #include "GroupsockHelper.hh"
00028 #endif
00029 
00030 // Segment data structures, used in the implementation below:
00031 
00032 #define SegmentBufSize 2000     /* conservatively high */
00033 
00034 class Segment {
00035 public:
00036   unsigned char buf[SegmentBufSize];
00037   unsigned char* dataStart() { return &buf[descriptorSize]; }
00038   unsigned frameSize; // if it's a non-ADU frame
00039   unsigned dataHere(); // if it's a non-ADU frame
00040 
00041   unsigned descriptorSize;
00042   static unsigned const headerSize;
00043   unsigned sideInfoSize, aduSize;
00044   unsigned backpointer;
00045 
00046   struct timeval presentationTime;
00047   unsigned durationInMicroseconds;
00048 };
00049 
00050 unsigned const Segment::headerSize = 4;
00051 
00052 #define SegmentQueueSize 20
00053 
00054 class SegmentQueue {
00055 public:
00056   SegmentQueue(Boolean directionIsToADU, Boolean includeADUdescriptors)
00057     : fDirectionIsToADU(directionIsToADU),
00058       fIncludeADUdescriptors(includeADUdescriptors) {
00059     reset();
00060   }
00061 
00062   Segment s[SegmentQueueSize];
00063 
00064   unsigned headIndex() {return fHeadIndex;}
00065   Segment& headSegment() {return s[fHeadIndex];}
00066 
00067   unsigned nextFreeIndex() {return fNextFreeIndex;}
00068   Segment& nextFreeSegment() {return s[fNextFreeIndex];}
00069   Boolean isEmpty() {return isEmptyOrFull() && totalDataSize() == 0;}
00070   Boolean isFull() {return isEmptyOrFull() && totalDataSize() > 0;}
00071 
00072   static unsigned nextIndex(unsigned ix) {return (ix+1)%SegmentQueueSize;}
00073   static unsigned prevIndex(unsigned ix) {return (ix+SegmentQueueSize-1)%SegmentQueueSize;}
00074 
00075   unsigned totalDataSize() {return fTotalDataSize;}
00076 
00077   void enqueueNewSegment(FramedSource* inputSource, FramedSource* usingSource);
00078 
00079   Boolean dequeue();
00080 
00081   Boolean insertDummyBeforeTail(unsigned backpointer);
00082 
00083   void reset() { fHeadIndex = fNextFreeIndex = fTotalDataSize = 0; }
00084 
00085 private:
00086   static void sqAfterGettingSegment(void* clientData,
00087                                     unsigned numBytesRead,
00088                                     unsigned numTruncatedBytes,
00089                                     struct timeval presentationTime,
00090                                     unsigned durationInMicroseconds);
00091 
00092   Boolean sqAfterGettingCommon(Segment& seg, unsigned numBytesRead);
00093   Boolean isEmptyOrFull() {return headIndex() == nextFreeIndex();}
00094 
00095   unsigned fHeadIndex, fNextFreeIndex, fTotalDataSize;
00096 
00097   // The following is used for asynchronous reads:
00098   FramedSource* fUsingSource;
00099 
00100   // This tells us whether the direction in which we're being used
00101   // is MP3->ADU, or vice-versa.  (This flag is used for debugging output.)
00102   Boolean fDirectionIsToADU;
00103 
00104   // The following is true iff we're used to enqueue incoming
00105   // ADU frames, and these have an ADU descriptor in front
00106   Boolean fIncludeADUdescriptors;
00107 };
00108 
00110 
00111 ADUFromMP3Source::ADUFromMP3Source(UsageEnvironment& env,
00112                                    FramedSource* inputSource,
00113                                    Boolean includeADUdescriptors)
00114   : FramedFilter(env, inputSource),
00115     fAreEnqueueingMP3Frame(False),
00116     fSegments(new SegmentQueue(True /* because we're MP3->ADU */,
00117                                False /*no descriptors in incoming frames*/)),
00118     fIncludeADUdescriptors(includeADUdescriptors),
00119     fTotalDataSizeBeforePreviousRead(0), fScale(1), fFrameCounter(0) {
00120 }
00121 
00122 ADUFromMP3Source::~ADUFromMP3Source() {
00123   delete fSegments;
00124 }
00125 
00126 
00127 char const* ADUFromMP3Source::MIMEtype() const {
00128   return "audio/MPA-ROBUST";
00129 }
00130 
00131 ADUFromMP3Source* ADUFromMP3Source::createNew(UsageEnvironment& env,
00132                                               FramedSource* inputSource,
00133                                               Boolean includeADUdescriptors) {
00134   // The source must be a MPEG audio source:
00135   if (strcmp(inputSource->MIMEtype(), "audio/MPEG") != 0) {
00136     env.setResultMsg(inputSource->name(), " is not an MPEG audio source");
00137     return NULL;
00138   }
00139 
00140   return new ADUFromMP3Source(env, inputSource, includeADUdescriptors);
00141 }
00142 
00143 void ADUFromMP3Source::resetInput() {
00144   fSegments->reset();
00145 }
00146 
00147 Boolean ADUFromMP3Source::setScaleFactor(int scale) {
00148   if (scale < 1) return False;
00149   fScale = scale;
00150   return True;
00151 }
00152 
00153 void ADUFromMP3Source::doGetNextFrame() {
00154   if (!fAreEnqueueingMP3Frame) {
00155     // Arrange to enqueue a new MP3 frame:
00156     fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize();
00157     fAreEnqueueingMP3Frame = True;
00158     fSegments->enqueueNewSegment(fInputSource, this);
00159   } else {
00160     // Deliver an ADU from a previously-read MP3 frame:
00161     fAreEnqueueingMP3Frame = False;
00162 
00163     if (!doGetNextFrame1()) {
00164       // An internal error occurred; act as if our source went away:
00165       FramedSource::handleClosure(this);
00166     }
00167   }
00168 }
00169 
00170 Boolean ADUFromMP3Source::doGetNextFrame1() {
00171   // First, check whether we have enough previously-read data to output an
00172   // ADU for the last-read MP3 frame:
00173   unsigned tailIndex;
00174   Segment* tailSeg;
00175   Boolean needMoreData;
00176 
00177   if (fSegments->isEmpty()) {
00178     needMoreData = True;
00179     tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings
00180   } else {
00181     tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00182     tailSeg = &(fSegments->s[tailIndex]);
00183 
00184     needMoreData
00185           = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far
00186       || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data
00187   }
00188 
00189   if (needMoreData) {
00190     // We don't have enough data to output an ADU from the last-read MP3
00191     // frame, so need to read another one and try again:
00192     doGetNextFrame();
00193     return True;
00194   }
00195 
00196   // Output an ADU from the tail segment:
00197   fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize;
00198   fPresentationTime = tailSeg->presentationTime;
00199   fDurationInMicroseconds = tailSeg->durationInMicroseconds;
00200   unsigned descriptorSize
00201     = fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0;
00202 #ifdef DEBUG
00203   fprintf(stderr, "m->a:outputting ADU %d<-%d, nbr:%d, sis:%d, dh:%d, (descriptor size: %d)\n", tailSeg->aduSize, tailSeg->backpointer, fFrameSize, tailSeg->sideInfoSize, tailSeg->dataHere(), descriptorSize);
00204 #endif
00205   if (descriptorSize + fFrameSize > fMaxSize) {
00206     envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room ("
00207             << descriptorSize + fFrameSize << ">"
00208             << fMaxSize << ")\n";
00209     fFrameSize = 0;
00210     return False;
00211   }
00212 
00213   unsigned char* toPtr = fTo;
00214   // output the ADU descriptor:
00215   if (fIncludeADUdescriptors) {
00216     fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize);
00217   }
00218 
00219   // output header and side info:
00220   memmove(toPtr, tailSeg->dataStart(),
00221           tailSeg->headerSize + tailSeg->sideInfoSize);
00222   toPtr += tailSeg->headerSize + tailSeg->sideInfoSize;
00223 
00224   // go back to the frame that contains the start of our data:
00225   unsigned offset = 0;
00226   unsigned i = tailIndex;
00227   unsigned prevBytes = tailSeg->backpointer;
00228   while (prevBytes > 0) {
00229     i = SegmentQueue::prevIndex(i);
00230     unsigned dataHere = fSegments->s[i].dataHere();
00231     if (dataHere < prevBytes) {
00232       prevBytes -= dataHere;
00233     } else {
00234       offset = dataHere - prevBytes;
00235       break;
00236     }
00237   }
00238 
00239   // dequeue any segments that we no longer need:
00240   while (fSegments->headIndex() != i) {
00241     fSegments->dequeue(); // we're done with it
00242   }
00243 
00244   unsigned bytesToUse = tailSeg->aduSize;
00245   while (bytesToUse > 0) {
00246     Segment& seg = fSegments->s[i];
00247     unsigned char* fromPtr
00248       = &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset];
00249     unsigned dataHere = seg.dataHere() - offset;
00250     unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse;
00251     memmove(toPtr, fromPtr, bytesUsedHere);
00252     bytesToUse -= bytesUsedHere;
00253     toPtr += bytesUsedHere;
00254     offset = 0;
00255     i = SegmentQueue::nextIndex(i);
00256   }
00257 
00258 
00259   if (fFrameCounter++%fScale == 0) {
00260     // Call our own 'after getting' function.  Because we're not a 'leaf'
00261     // source, we can call this directly, without risking infinite recursion.
00262     afterGetting(this);
00263   } else {
00264     // Don't use this frame; get another one:
00265     doGetNextFrame();
00266   }
00267 
00268   return True;
00269 }
00270 
00271 
00273 
00274 MP3FromADUSource::MP3FromADUSource(UsageEnvironment& env,
00275                                    FramedSource* inputSource,
00276                                    Boolean includeADUdescriptors)
00277   : FramedFilter(env, inputSource),
00278     fAreEnqueueingADU(False),
00279     fSegments(new SegmentQueue(False /* because we're ADU->MP3 */,
00280                                includeADUdescriptors)) {
00281 }
00282 
00283 MP3FromADUSource::~MP3FromADUSource() {
00284   delete fSegments;
00285 }
00286 
00287 char const* MP3FromADUSource::MIMEtype() const {
00288   return "audio/MPEG";
00289 }
00290 
00291 MP3FromADUSource* MP3FromADUSource::createNew(UsageEnvironment& env,
00292                                               FramedSource* inputSource,
00293                                               Boolean includeADUdescriptors) {
00294   // The source must be an MP3 ADU source:
00295   if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) {
00296     env.setResultMsg(inputSource->name(), " is not an MP3 ADU source");
00297     return NULL;
00298   }
00299 
00300   return new MP3FromADUSource(env, inputSource, includeADUdescriptors);
00301 }
00302 
00303 
00304 void MP3FromADUSource::doGetNextFrame() {
00305   if (fAreEnqueueingADU) insertDummyADUsIfNecessary();
00306   fAreEnqueueingADU = False;
00307 
00308   if (needToGetAnADU()) {
00309     // Before returning a frame, we must enqueue at least one ADU:
00310 #ifdef TEST_LOSS
00311   NOTE: This code no longer works, because it uses synchronous reads,
00312   which are no longer supported.
00313     static unsigned const framesPerPacket = 10;
00314     static unsigned const frameCount = 0;
00315     static Boolean packetIsLost;
00316     while (1) {
00317       if ((frameCount++)%framesPerPacket == 0) {
00318         packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
00319       }
00320 
00321       if (packetIsLost) {
00322         // Read and discard the next input frame (that would be part of
00323         // a lost packet):
00324         Segment dummySegment;
00325         unsigned numBytesRead;
00326         struct timeval presentationTime;
00327         // (this works only if the source can be read synchronously)
00328         fInputSource->syncGetNextFrame(dummySegment.buf,
00329                                        sizeof dummySegment.buf, numBytesRead,
00330                                        presentationTime);
00331       } else {
00332         break; // from while (1)
00333       }
00334     }
00335 #endif
00336 
00337     fAreEnqueueingADU = True;
00338     fSegments->enqueueNewSegment(fInputSource, this);
00339   } else {
00340     // Return a frame now:
00341     generateFrameFromHeadADU();
00342         // sets fFrameSize, fPresentationTime, and fDurationInMicroseconds
00343 
00344     // Call our own 'after getting' function.  Because we're not a 'leaf'
00345     // source, we can call this directly, without risking infinite recursion.
00346     afterGetting(this);
00347   }
00348 }
00349 
00350 Boolean MP3FromADUSource::needToGetAnADU() {
00351   // Check whether we need to first enqueue a new ADU before we
00352   // can generate a frame for our head ADU.
00353   Boolean needToEnqueue = True;
00354 
00355   if (!fSegments->isEmpty()) {
00356     unsigned index = fSegments->headIndex();
00357     Segment* seg = &(fSegments->headSegment());
00358     int const endOfHeadFrame = (int) seg->dataHere();
00359     unsigned frameOffset = 0;
00360 
00361     while (1) {
00362       int endOfData = frameOffset - seg->backpointer + seg->aduSize;
00363       if (endOfData >= endOfHeadFrame) {
00364         // We already have enough data to generate a frame
00365         needToEnqueue = False;
00366         break;
00367       }
00368 
00369       frameOffset += seg->dataHere();
00370       index = SegmentQueue::nextIndex(index);
00371       if (index == fSegments->nextFreeIndex()) break;
00372       seg = &(fSegments->s[index]);
00373     }
00374   }
00375 
00376   return needToEnqueue;
00377 }
00378 
00379 void MP3FromADUSource::insertDummyADUsIfNecessary() {
00380   if (fSegments->isEmpty()) return; // shouldn't happen
00381 
00382   // The tail segment (ADU) is assumed to have been recently
00383   // enqueued.  If its backpointer would overlap the data
00384   // of the previous ADU, then we need to insert one or more
00385   // empty, 'dummy' ADUs ahead of it.  (This situation should occur
00386   // only if an intermediate ADU was lost.)
00387 
00388   unsigned tailIndex
00389     = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00390   Segment* tailSeg = &(fSegments->s[tailIndex]);
00391 
00392   while (1) {
00393     unsigned prevADUend; // relative to the start of the new ADU
00394     if (fSegments->headIndex() != tailIndex) {
00395       // there is a previous segment
00396       unsigned prevIndex = SegmentQueue::prevIndex(tailIndex);
00397       Segment& prevSegment = fSegments->s[prevIndex];
00398       prevADUend = prevSegment.dataHere() + prevSegment.backpointer;
00399       if (prevSegment.aduSize > prevADUend) {
00400         // shouldn't happen if the previous ADU was well-formed
00401         prevADUend = 0;
00402       } else {
00403         prevADUend -= prevSegment.aduSize;
00404       }
00405     } else {
00406       prevADUend = 0;
00407     }
00408 
00409     if (tailSeg->backpointer > prevADUend) {
00410       // We need to insert a dummy ADU in front of the tail
00411 #ifdef DEBUG
00412       fprintf(stderr, "a->m:need to insert a dummy ADU (%d, %d, %d) [%d, %d]\n", tailSeg->backpointer, prevADUend, tailSeg->dataHere(), fSegments->headIndex(), fSegments->nextFreeIndex());
00413 #endif
00414       tailIndex = fSegments->nextFreeIndex();
00415       if (!fSegments->insertDummyBeforeTail(prevADUend)) return;
00416       tailSeg = &(fSegments->s[tailIndex]);
00417     } else {
00418       break; // no more dummy ADUs need to be inserted
00419     }
00420   }
00421 }
00422 
00423 Boolean MP3FromADUSource::generateFrameFromHeadADU() {
00424     // Output a frame for the head ADU:
00425     if (fSegments->isEmpty()) return False;
00426     unsigned index = fSegments->headIndex();
00427     Segment* seg = &(fSegments->headSegment());
00428 #ifdef DEBUG
00429     fprintf(stderr, "a->m:outputting frame for %d<-%d (fs %d, dh %d), (descriptorSize: %d)\n", seg->aduSize, seg->backpointer, seg->frameSize, seg->dataHere(), seg->descriptorSize);
00430 #endif
00431     unsigned char* toPtr = fTo;
00432 
00433     // output header and side info:
00434     fFrameSize = seg->frameSize;
00435     fPresentationTime = seg->presentationTime;
00436     fDurationInMicroseconds = seg->durationInMicroseconds;
00437     memmove(toPtr, seg->dataStart(), seg->headerSize + seg->sideInfoSize);
00438     toPtr += seg->headerSize + seg->sideInfoSize;
00439 
00440     // zero out the rest of the frame, in case ADU data doesn't fill it all in
00441     unsigned bytesToZero = seg->dataHere();
00442     for (unsigned i = 0; i < bytesToZero; ++i) {
00443       toPtr[i] = '\0';
00444     }
00445 
00446     // Fill in the frame with appropriate ADU data from this and
00447     // subsequent ADUs:
00448     unsigned frameOffset = 0;
00449     unsigned toOffset = 0;
00450     unsigned const endOfHeadFrame = seg->dataHere();
00451 
00452     while (toOffset < endOfHeadFrame) {
00453       int startOfData = frameOffset - seg->backpointer;
00454       if (startOfData > (int)endOfHeadFrame) break; // no more ADUs needed
00455 
00456       int endOfData = startOfData + seg->aduSize;
00457       if (endOfData > (int)endOfHeadFrame) {
00458         endOfData = endOfHeadFrame;
00459       }
00460 
00461       unsigned fromOffset;
00462       if (startOfData <= (int)toOffset) {
00463         fromOffset = toOffset - startOfData;
00464         startOfData = toOffset;
00465         if (endOfData < startOfData) endOfData = startOfData;
00466       } else {
00467         fromOffset = 0;
00468 
00469         // we may need some padding bytes beforehand
00470         unsigned bytesToZero = startOfData - toOffset;
00471 #ifdef DEBUG
00472         if (bytesToZero > 0) fprintf(stderr, "a->m:outputting %d zero bytes (%d, %d, %d, %d)\n", bytesToZero, startOfData, toOffset, frameOffset, seg->backpointer);
00473 #endif
00474         toOffset += bytesToZero;
00475       }
00476 
00477       unsigned char* fromPtr
00478         = &seg->dataStart()[seg->headerSize + seg->sideInfoSize + fromOffset];
00479       unsigned bytesUsedHere = endOfData - startOfData;
00480 #ifdef DEBUG
00481       if (bytesUsedHere > 0) fprintf(stderr, "a->m:outputting %d bytes from %d<-%d\n", bytesUsedHere, seg->aduSize, seg->backpointer);
00482 #endif
00483       memmove(toPtr + toOffset, fromPtr, bytesUsedHere);
00484       toOffset += bytesUsedHere;
00485 
00486       frameOffset += seg->dataHere();
00487       index = SegmentQueue::nextIndex(index);
00488       if (index == fSegments->nextFreeIndex()) break;
00489       seg = &(fSegments->s[index]);
00490     }
00491 
00492     fSegments->dequeue();
00493 
00494     return True;
00495 }
00496 
00497 
00499 
00500 unsigned Segment::dataHere() {
00501   int result = frameSize - (headerSize + sideInfoSize);
00502   if (result < 0) {
00503     return 0;
00504   }
00505 
00506   return (unsigned)result;
00507 }
00508 
00510 
00511 void SegmentQueue::enqueueNewSegment(FramedSource* inputSource,
00512                                      FramedSource* usingSource) {
00513   if (isFull()) {
00514     usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n";
00515     FramedSource::handleClosure(usingSource);
00516     return;
00517   }
00518 
00519   fUsingSource = usingSource;
00520 
00521   Segment& seg = nextFreeSegment();
00522   inputSource->getNextFrame(seg.buf, sizeof seg.buf,
00523                             sqAfterGettingSegment, this,
00524                             FramedSource::handleClosure, usingSource);
00525 }
00526 
00527 void SegmentQueue::sqAfterGettingSegment(void* clientData,
00528                                          unsigned numBytesRead,
00529                                          unsigned /*numTruncatedBytes*/,
00530                                          struct timeval presentationTime,
00531                                          unsigned durationInMicroseconds) {
00532   SegmentQueue* segQueue = (SegmentQueue*)clientData;
00533   Segment& seg = segQueue->nextFreeSegment();
00534 
00535   seg.presentationTime = presentationTime;
00536   seg.durationInMicroseconds = durationInMicroseconds;
00537 
00538   if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) {
00539 #ifdef DEBUG
00540     char const* direction = segQueue->fDirectionIsToADU ? "m->a" : "a->m";
00541     fprintf(stderr, "%s:read frame %d<-%d, fs:%d, sis:%d, dh:%d, (descriptor size: %d)\n", direction, seg.aduSize, seg.backpointer, seg.frameSize, seg.sideInfoSize, seg.dataHere(), seg.descriptorSize);
00542 #endif
00543   }
00544 
00545   // Continue our original calling source where it left off:
00546   segQueue->fUsingSource->doGetNextFrame();
00547 }
00548 
00549 // Common code called after a new segment is enqueued
00550 Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,
00551                                            unsigned numBytesRead) {
00552   unsigned char* fromPtr = seg.buf;
00553 
00554   if (fIncludeADUdescriptors) {
00555     // The newly-read data is assumed to be an ADU with a descriptor
00556     // in front
00557     (void)ADUdescriptor::getRemainingFrameSize(fromPtr);
00558     seg.descriptorSize = (unsigned)(fromPtr-seg.buf);
00559   } else {
00560     seg.descriptorSize = 0;
00561   }
00562 
00563   // parse the MP3-specific info in the frame to get the ADU params
00564   unsigned hdr;
00565   MP3SideInfo sideInfo;
00566   if (!GetADUInfoFromMP3Frame(fromPtr, numBytesRead,
00567                               hdr, seg.frameSize,
00568                               sideInfo, seg.sideInfoSize,
00569                               seg.backpointer, seg.aduSize)) {
00570     return False;
00571   }
00572 
00573   // If we've just read an ADU (rather than a regular MP3 frame), then use the
00574   // entire "numBytesRead" data for the 'aduSize', so that we include any
00575   // 'ancillary data' that may be present at the end of the ADU:
00576   if (!fDirectionIsToADU) {
00577     unsigned newADUSize
00578       = numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize;
00579     if (newADUSize > seg.aduSize) seg.aduSize = newADUSize;
00580   }
00581   fTotalDataSize += seg.dataHere();
00582   fNextFreeIndex = nextIndex(fNextFreeIndex);
00583 
00584   return True;
00585 }
00586 
00587 Boolean SegmentQueue::dequeue() {
00588   if (isEmpty()) {
00589     fUsingSource->envir() << "SegmentQueue::dequeue(): underflow!\n";
00590     return False;
00591   }
00592 
00593   Segment& seg = s[headIndex()];
00594   fTotalDataSize -= seg.dataHere();
00595   fHeadIndex = nextIndex(fHeadIndex);
00596   return True;
00597 }
00598 
00599 Boolean SegmentQueue::insertDummyBeforeTail(unsigned backpointer) {
00600   if (isEmptyOrFull()) return False;
00601 
00602   // Copy the current tail segment to its new position, then modify the
00603   // old tail segment to be a 'dummy' ADU
00604 
00605   unsigned newTailIndex = nextFreeIndex();
00606   Segment& newTailSeg = s[newTailIndex];
00607 
00608   unsigned oldTailIndex = prevIndex(newTailIndex);
00609   Segment& oldTailSeg = s[oldTailIndex];
00610 
00611   newTailSeg = oldTailSeg; // structure copy
00612 
00613   // Begin by setting (replacing) the ADU descriptor of the dummy ADU:
00614   unsigned char* ptr = oldTailSeg.buf;
00615   if (fIncludeADUdescriptors) {
00616     unsigned remainingFrameSize
00617       = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 /* 0-size ADU */;
00618     unsigned currentDescriptorSize = oldTailSeg.descriptorSize;
00619 
00620     if (currentDescriptorSize == 2) {
00621       ADUdescriptor::generateTwoByteDescriptor(ptr, remainingFrameSize);
00622     } else {
00623       (void)ADUdescriptor::generateDescriptor(ptr, remainingFrameSize);
00624     }
00625   }
00626 
00627   // Then zero out the side info of the dummy frame:
00628   if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize,
00629                           backpointer)) return False;
00630 
00631   unsigned dummyNumBytesRead
00632     = oldTailSeg.descriptorSize + 4/*header size*/ + oldTailSeg.sideInfoSize;
00633   return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead);
00634 }

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