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-2012 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     fIncludeADUdescriptors(includeADUdescriptors) {
00282 }
00283 
00284 MP3FromADUSource::~MP3FromADUSource() {
00285   delete fSegments;
00286 }
00287 
00288 char const* MP3FromADUSource::MIMEtype() const {
00289   return "audio/MPEG";
00290 }
00291 
00292 MP3FromADUSource* MP3FromADUSource::createNew(UsageEnvironment& env,
00293                                               FramedSource* inputSource,
00294                                               Boolean includeADUdescriptors) {
00295   // The source must be an MP3 ADU source:
00296   if (strcmp(inputSource->MIMEtype(), "audio/MPA-ROBUST") != 0) {
00297     env.setResultMsg(inputSource->name(), " is not an MP3 ADU source");
00298     return NULL;
00299   }
00300 
00301   return new MP3FromADUSource(env, inputSource, includeADUdescriptors);
00302 }
00303 
00304 
00305 void MP3FromADUSource::doGetNextFrame() {
00306   if (fAreEnqueueingADU) insertDummyADUsIfNecessary();
00307   fAreEnqueueingADU = False;
00308 
00309   if (needToGetAnADU()) {
00310     // Before returning a frame, we must enqueue at least one ADU:
00311 #ifdef TEST_LOSS
00312   NOTE: This code no longer works, because it uses synchronous reads,
00313   which are no longer supported.
00314     static unsigned const framesPerPacket = 10;
00315     static unsigned const frameCount = 0;
00316     static Boolean packetIsLost;
00317     while (1) {
00318       if ((frameCount++)%framesPerPacket == 0) {
00319         packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss #####
00320       }
00321 
00322       if (packetIsLost) {
00323         // Read and discard the next input frame (that would be part of
00324         // a lost packet):
00325         Segment dummySegment;
00326         unsigned numBytesRead;
00327         struct timeval presentationTime;
00328         // (this works only if the source can be read synchronously)
00329         fInputSource->syncGetNextFrame(dummySegment.buf,
00330                                        sizeof dummySegment.buf, numBytesRead,
00331                                        presentationTime);
00332       } else {
00333         break; // from while (1)
00334       }
00335     }
00336 #endif
00337 
00338     fAreEnqueueingADU = True;
00339     fSegments->enqueueNewSegment(fInputSource, this);
00340   } else {
00341     // Return a frame now:
00342     generateFrameFromHeadADU();
00343         // sets fFrameSize, fPresentationTime, and fDurationInMicroseconds
00344 
00345     // Call our own 'after getting' function.  Because we're not a 'leaf'
00346     // source, we can call this directly, without risking infinite recursion.
00347     afterGetting(this);
00348   }
00349 }
00350 
00351 Boolean MP3FromADUSource::needToGetAnADU() {
00352   // Check whether we need to first enqueue a new ADU before we
00353   // can generate a frame for our head ADU.
00354   Boolean needToEnqueue = True;
00355 
00356   if (!fSegments->isEmpty()) {
00357     unsigned index = fSegments->headIndex();
00358     Segment* seg = &(fSegments->headSegment());
00359     int const endOfHeadFrame = (int) seg->dataHere();
00360     unsigned frameOffset = 0;
00361 
00362     while (1) {
00363       int endOfData = frameOffset - seg->backpointer + seg->aduSize;
00364       if (endOfData >= endOfHeadFrame) {
00365         // We already have enough data to generate a frame
00366         needToEnqueue = False;
00367         break;
00368       }
00369 
00370       frameOffset += seg->dataHere();
00371       index = SegmentQueue::nextIndex(index);
00372       if (index == fSegments->nextFreeIndex()) break;
00373       seg = &(fSegments->s[index]);
00374     }
00375   }
00376 
00377   return needToEnqueue;
00378 }
00379 
00380 void MP3FromADUSource::insertDummyADUsIfNecessary() {
00381   if (fSegments->isEmpty()) return; // shouldn't happen
00382 
00383   // The tail segment (ADU) is assumed to have been recently
00384   // enqueued.  If its backpointer would overlap the data
00385   // of the previous ADU, then we need to insert one or more
00386   // empty, 'dummy' ADUs ahead of it.  (This situation should occur
00387   // only if an intermediate ADU was lost.)
00388 
00389   unsigned tailIndex
00390     = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00391   Segment* tailSeg = &(fSegments->s[tailIndex]);
00392 
00393   while (1) {
00394     unsigned prevADUend; // relative to the start of the new ADU
00395     if (fSegments->headIndex() != tailIndex) {
00396       // there is a previous segment
00397       unsigned prevIndex = SegmentQueue::prevIndex(tailIndex);
00398       Segment& prevSegment = fSegments->s[prevIndex];
00399       prevADUend = prevSegment.dataHere() + prevSegment.backpointer;
00400       if (prevSegment.aduSize > prevADUend) {
00401         // shouldn't happen if the previous ADU was well-formed
00402         prevADUend = 0;
00403       } else {
00404         prevADUend -= prevSegment.aduSize;
00405       }
00406     } else {
00407       prevADUend = 0;
00408     }
00409 
00410     if (tailSeg->backpointer > prevADUend) {
00411       // We need to insert a dummy ADU in front of the tail
00412 #ifdef DEBUG
00413       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());
00414 #endif
00415       tailIndex = fSegments->nextFreeIndex();
00416       if (!fSegments->insertDummyBeforeTail(prevADUend)) return;
00417       tailSeg = &(fSegments->s[tailIndex]);
00418     } else {
00419       break; // no more dummy ADUs need to be inserted
00420     }
00421   }
00422 }
00423 
00424 Boolean MP3FromADUSource::generateFrameFromHeadADU() {
00425     // Output a frame for the head ADU:
00426     if (fSegments->isEmpty()) return False;
00427     unsigned index = fSegments->headIndex();
00428     Segment* seg = &(fSegments->headSegment());
00429 #ifdef DEBUG
00430     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);
00431 #endif
00432     unsigned char* toPtr = fTo;
00433 
00434     // output header and side info:
00435     fFrameSize = seg->frameSize;
00436     fPresentationTime = seg->presentationTime;
00437     fDurationInMicroseconds = seg->durationInMicroseconds;
00438     memmove(toPtr, seg->dataStart(), seg->headerSize + seg->sideInfoSize);
00439     toPtr += seg->headerSize + seg->sideInfoSize;
00440 
00441     // zero out the rest of the frame, in case ADU data doesn't fill it all in
00442     unsigned bytesToZero = seg->dataHere();
00443     for (unsigned i = 0; i < bytesToZero; ++i) {
00444       toPtr[i] = '\0';
00445     }
00446 
00447     // Fill in the frame with appropriate ADU data from this and
00448     // subsequent ADUs:
00449     unsigned frameOffset = 0;
00450     unsigned toOffset = 0;
00451     unsigned const endOfHeadFrame = seg->dataHere();
00452 
00453     while (toOffset < endOfHeadFrame) {
00454       int startOfData = frameOffset - seg->backpointer;
00455       if (startOfData > (int)endOfHeadFrame) break; // no more ADUs needed
00456 
00457       int endOfData = startOfData + seg->aduSize;
00458       if (endOfData > (int)endOfHeadFrame) {
00459         endOfData = endOfHeadFrame;
00460       }
00461 
00462       unsigned fromOffset;
00463       if (startOfData <= (int)toOffset) {
00464         fromOffset = toOffset - startOfData;
00465         startOfData = toOffset;
00466         if (endOfData < startOfData) endOfData = startOfData;
00467       } else {
00468         fromOffset = 0;
00469 
00470         // we may need some padding bytes beforehand
00471         unsigned bytesToZero = startOfData - toOffset;
00472 #ifdef DEBUG
00473         if (bytesToZero > 0) fprintf(stderr, "a->m:outputting %d zero bytes (%d, %d, %d, %d)\n", bytesToZero, startOfData, toOffset, frameOffset, seg->backpointer);
00474 #endif
00475         toOffset += bytesToZero;
00476       }
00477 
00478       unsigned char* fromPtr
00479         = &seg->dataStart()[seg->headerSize + seg->sideInfoSize + fromOffset];
00480       unsigned bytesUsedHere = endOfData - startOfData;
00481 #ifdef DEBUG
00482       if (bytesUsedHere > 0) fprintf(stderr, "a->m:outputting %d bytes from %d<-%d\n", bytesUsedHere, seg->aduSize, seg->backpointer);
00483 #endif
00484       memmove(toPtr + toOffset, fromPtr, bytesUsedHere);
00485       toOffset += bytesUsedHere;
00486 
00487       frameOffset += seg->dataHere();
00488       index = SegmentQueue::nextIndex(index);
00489       if (index == fSegments->nextFreeIndex()) break;
00490       seg = &(fSegments->s[index]);
00491     }
00492 
00493     fSegments->dequeue();
00494 
00495     return True;
00496 }
00497 
00498 
00500 
00501 unsigned Segment::dataHere() {
00502   int result = frameSize - (headerSize + sideInfoSize);
00503   if (result < 0) {
00504     return 0;
00505   }
00506 
00507   return (unsigned)result;
00508 }
00509 
00511 
00512 void SegmentQueue::enqueueNewSegment(FramedSource* inputSource,
00513                                      FramedSource* usingSource) {
00514   if (isFull()) {
00515     usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n";
00516     FramedSource::handleClosure(usingSource);
00517     return;
00518   }
00519 
00520   fUsingSource = usingSource;
00521 
00522   Segment& seg = nextFreeSegment();
00523   inputSource->getNextFrame(seg.buf, sizeof seg.buf,
00524                             sqAfterGettingSegment, this,
00525                             FramedSource::handleClosure, usingSource);
00526 }
00527 
00528 void SegmentQueue::sqAfterGettingSegment(void* clientData,
00529                                          unsigned numBytesRead,
00530                                          unsigned /*numTruncatedBytes*/,
00531                                          struct timeval presentationTime,
00532                                          unsigned durationInMicroseconds) {
00533   SegmentQueue* segQueue = (SegmentQueue*)clientData;
00534   Segment& seg = segQueue->nextFreeSegment();
00535 
00536   seg.presentationTime = presentationTime;
00537   seg.durationInMicroseconds = durationInMicroseconds;
00538 
00539   if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) {
00540 #ifdef DEBUG
00541     char const* direction = segQueue->fDirectionIsToADU ? "m->a" : "a->m";
00542     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);
00543 #endif
00544   }
00545 
00546   // Continue our original calling source where it left off:
00547   segQueue->fUsingSource->doGetNextFrame();
00548 }
00549 
00550 // Common code called after a new segment is enqueued
00551 Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,
00552                                            unsigned numBytesRead) {
00553   unsigned char* fromPtr = seg.buf;
00554 
00555   if (fIncludeADUdescriptors) {
00556     // The newly-read data is assumed to be an ADU with a descriptor
00557     // in front
00558     (void)ADUdescriptor::getRemainingFrameSize(fromPtr);
00559     seg.descriptorSize = (unsigned)(fromPtr-seg.buf);
00560   } else {
00561     seg.descriptorSize = 0;
00562   }
00563 
00564   // parse the MP3-specific info in the frame to get the ADU params
00565   unsigned hdr;
00566   MP3SideInfo sideInfo;
00567   if (!GetADUInfoFromMP3Frame(fromPtr, numBytesRead,
00568                               hdr, seg.frameSize,
00569                               sideInfo, seg.sideInfoSize,
00570                               seg.backpointer, seg.aduSize)) {
00571     return False;
00572   }
00573 
00574   // If we've just read an ADU (rather than a regular MP3 frame), then use the
00575   // entire "numBytesRead" data for the 'aduSize', so that we include any
00576   // 'ancillary data' that may be present at the end of the ADU:
00577   if (!fDirectionIsToADU) {
00578     unsigned newADUSize
00579       = numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize;
00580     if (newADUSize > seg.aduSize) seg.aduSize = newADUSize;
00581   }
00582   fTotalDataSize += seg.dataHere();
00583   fNextFreeIndex = nextIndex(fNextFreeIndex);
00584 
00585   return True;
00586 }
00587 
00588 Boolean SegmentQueue::dequeue() {
00589   if (isEmpty()) {
00590     fUsingSource->envir() << "SegmentQueue::dequeue(): underflow!\n";
00591     return False;
00592   }
00593 
00594   Segment& seg = s[headIndex()];
00595   fTotalDataSize -= seg.dataHere();
00596   fHeadIndex = nextIndex(fHeadIndex);
00597   return True;
00598 }
00599 
00600 Boolean SegmentQueue::insertDummyBeforeTail(unsigned backpointer) {
00601   if (isEmptyOrFull()) return False;
00602 
00603   // Copy the current tail segment to its new position, then modify the
00604   // old tail segment to be a 'dummy' ADU
00605 
00606   unsigned newTailIndex = nextFreeIndex();
00607   Segment& newTailSeg = s[newTailIndex];
00608 
00609   unsigned oldTailIndex = prevIndex(newTailIndex);
00610   Segment& oldTailSeg = s[oldTailIndex];
00611 
00612   newTailSeg = oldTailSeg; // structure copy
00613 
00614   // Begin by setting (replacing) the ADU descriptor of the dummy ADU:
00615   unsigned char* ptr = oldTailSeg.buf;
00616   if (fIncludeADUdescriptors) {
00617     unsigned remainingFrameSize
00618       = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 /* 0-size ADU */;
00619     unsigned currentDescriptorSize = oldTailSeg.descriptorSize;
00620 
00621     if (currentDescriptorSize == 2) {
00622       ADUdescriptor::generateTwoByteDescriptor(ptr, remainingFrameSize);
00623     } else {
00624       (void)ADUdescriptor::generateDescriptor(ptr, remainingFrameSize);
00625     }
00626   }
00627 
00628   // Then zero out the side info of the dummy frame:
00629   if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize,
00630                           backpointer)) return False;
00631 
00632   unsigned dummyNumBytesRead
00633     = oldTailSeg.descriptorSize + 4/*header size*/ + oldTailSeg.sideInfoSize;
00634   return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead);
00635 }

Generated on Thu May 17 07:11:46 2012 for live by  doxygen 1.5.2