00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00031
00032 #define SegmentBufSize 2000
00033
00034 class Segment {
00035 public:
00036 unsigned char buf[SegmentBufSize];
00037 unsigned char* dataStart() { return &buf[descriptorSize]; }
00038 unsigned frameSize;
00039 unsigned dataHere();
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
00098 FramedSource* fUsingSource;
00099
00100
00101
00102 Boolean fDirectionIsToADU;
00103
00104
00105
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 ,
00117 False )),
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
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
00156 fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize();
00157 fAreEnqueueingMP3Frame = True;
00158 fSegments->enqueueNewSegment(fInputSource, this);
00159 } else {
00160
00161 fAreEnqueueingMP3Frame = False;
00162
00163 if (!doGetNextFrame1()) {
00164
00165 FramedSource::handleClosure(this);
00166 }
00167 }
00168 }
00169
00170 Boolean ADUFromMP3Source::doGetNextFrame1() {
00171
00172
00173 unsigned tailIndex;
00174 Segment* tailSeg;
00175 Boolean needMoreData;
00176
00177 if (fSegments->isEmpty()) {
00178 needMoreData = True;
00179 tailSeg = NULL; tailIndex = 0;
00180 } else {
00181 tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00182 tailSeg = &(fSegments->s[tailIndex]);
00183
00184 needMoreData
00185 = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer
00186 || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize;
00187 }
00188
00189 if (needMoreData) {
00190
00191
00192 doGetNextFrame();
00193 return True;
00194 }
00195
00196
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
00215 if (fIncludeADUdescriptors) {
00216 fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize);
00217 }
00218
00219
00220 memmove(toPtr, tailSeg->dataStart(),
00221 tailSeg->headerSize + tailSeg->sideInfoSize);
00222 toPtr += tailSeg->headerSize + tailSeg->sideInfoSize;
00223
00224
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
00240 while (fSegments->headIndex() != i) {
00241 fSegments->dequeue();
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
00261
00262 afterGetting(this);
00263 } else {
00264
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 ,
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
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
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);
00319 }
00320
00321 if (packetIsLost) {
00322
00323
00324 Segment dummySegment;
00325 unsigned numBytesRead;
00326 struct timeval presentationTime;
00327
00328 fInputSource->syncGetNextFrame(dummySegment.buf,
00329 sizeof dummySegment.buf, numBytesRead,
00330 presentationTime);
00331 } else {
00332 break;
00333 }
00334 }
00335 #endif
00336
00337 fAreEnqueueingADU = True;
00338 fSegments->enqueueNewSegment(fInputSource, this);
00339 } else {
00340
00341 generateFrameFromHeadADU();
00342
00343
00344
00345
00346 afterGetting(this);
00347 }
00348 }
00349
00350 Boolean MP3FromADUSource::needToGetAnADU() {
00351
00352
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
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;
00381
00382
00383
00384
00385
00386
00387
00388 unsigned tailIndex
00389 = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00390 Segment* tailSeg = &(fSegments->s[tailIndex]);
00391
00392 while (1) {
00393 unsigned prevADUend;
00394 if (fSegments->headIndex() != tailIndex) {
00395
00396 unsigned prevIndex = SegmentQueue::prevIndex(tailIndex);
00397 Segment& prevSegment = fSegments->s[prevIndex];
00398 prevADUend = prevSegment.dataHere() + prevSegment.backpointer;
00399 if (prevSegment.aduSize > prevADUend) {
00400
00401 prevADUend = 0;
00402 } else {
00403 prevADUend -= prevSegment.aduSize;
00404 }
00405 } else {
00406 prevADUend = 0;
00407 }
00408
00409 if (tailSeg->backpointer > prevADUend) {
00410
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;
00419 }
00420 }
00421 }
00422
00423 Boolean MP3FromADUSource::generateFrameFromHeadADU() {
00424
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
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
00441 unsigned bytesToZero = seg->dataHere();
00442 for (unsigned i = 0; i < bytesToZero; ++i) {
00443 toPtr[i] = '\0';
00444 }
00445
00446
00447
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;
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
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 ,
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
00546 segQueue->fUsingSource->doGetNextFrame();
00547 }
00548
00549
00550 Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,
00551 unsigned numBytesRead) {
00552 unsigned char* fromPtr = seg.buf;
00553
00554 if (fIncludeADUdescriptors) {
00555
00556
00557 (void)ADUdescriptor::getRemainingFrameSize(fromPtr);
00558 seg.descriptorSize = (unsigned)(fromPtr-seg.buf);
00559 } else {
00560 seg.descriptorSize = 0;
00561 }
00562
00563
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
00574
00575
00576 if (!fDirectionIsToADU) {
00577 unsigned newADUSize
00578 = numBytesRead - seg.descriptorSize - 4 - 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
00603
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;
00612
00613
00614 unsigned char* ptr = oldTailSeg.buf;
00615 if (fIncludeADUdescriptors) {
00616 unsigned remainingFrameSize
00617 = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 ;
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
00628 if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize,
00629 backpointer)) return False;
00630
00631 unsigned dummyNumBytesRead
00632 = oldTailSeg.descriptorSize + 4 + oldTailSeg.sideInfoSize;
00633 return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead);
00634 }