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 10
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 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
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
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);
00320 }
00321
00322 if (packetIsLost) {
00323
00324
00325 Segment dummySegment;
00326 unsigned numBytesRead;
00327 struct timeval presentationTime;
00328
00329 fInputSource->syncGetNextFrame(dummySegment.buf,
00330 sizeof dummySegment.buf, numBytesRead,
00331 presentationTime);
00332 } else {
00333 break;
00334 }
00335 }
00336 #endif
00337
00338 fAreEnqueueingADU = True;
00339 fSegments->enqueueNewSegment(fInputSource, this);
00340 } else {
00341
00342 generateFrameFromHeadADU();
00343
00344
00345
00346
00347 afterGetting(this);
00348 }
00349 }
00350
00351 Boolean MP3FromADUSource::needToGetAnADU() {
00352
00353
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
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;
00382
00383
00384
00385
00386
00387
00388
00389 unsigned tailIndex
00390 = SegmentQueue::prevIndex(fSegments->nextFreeIndex());
00391 Segment* tailSeg = &(fSegments->s[tailIndex]);
00392
00393 while (1) {
00394 unsigned prevADUend;
00395 if (fSegments->headIndex() != tailIndex) {
00396
00397 unsigned prevIndex = SegmentQueue::prevIndex(tailIndex);
00398 Segment& prevSegment = fSegments->s[prevIndex];
00399 prevADUend = prevSegment.dataHere() + prevSegment.backpointer;
00400 if (prevSegment.aduSize > prevADUend) {
00401
00402 prevADUend = 0;
00403 } else {
00404 prevADUend -= prevSegment.aduSize;
00405 }
00406 } else {
00407 prevADUend = 0;
00408 }
00409
00410 if (tailSeg->backpointer > prevADUend) {
00411
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;
00420 }
00421 }
00422 }
00423
00424 Boolean MP3FromADUSource::generateFrameFromHeadADU() {
00425
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
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
00442 unsigned bytesToZero = seg->dataHere();
00443 for (unsigned i = 0; i < bytesToZero; ++i) {
00444 toPtr[i] = '\0';
00445 }
00446
00447
00448
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;
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
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 ,
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
00547 segQueue->fUsingSource->doGetNextFrame();
00548 }
00549
00550
00551 Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,
00552 unsigned numBytesRead) {
00553 unsigned char* fromPtr = seg.buf;
00554
00555 if (fIncludeADUdescriptors) {
00556
00557
00558 (void)ADUdescriptor::getRemainingFrameSize(fromPtr);
00559 seg.descriptorSize = (unsigned)(fromPtr-seg.buf);
00560 } else {
00561 seg.descriptorSize = 0;
00562 }
00563
00564
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
00575
00576
00577 if (!fDirectionIsToADU) {
00578 unsigned newADUSize
00579 = numBytesRead - seg.descriptorSize - 4 - 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
00604
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;
00613
00614
00615 unsigned char* ptr = oldTailSeg.buf;
00616 if (fIncludeADUdescriptors) {
00617 unsigned remainingFrameSize
00618 = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 ;
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
00629 if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize,
00630 backpointer)) return False;
00631
00632 unsigned dummyNumBytesRead
00633 = oldTailSeg.descriptorSize + 4 + oldTailSeg.sideInfoSize;
00634 return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead);
00635 }