📄 mp3adu.cpp
字号:
packetIsLost = (our_random()%10 == 0); // simulate 10% packet loss ##### } if (packetIsLost) { // Read and discard the next input frame (that would be part of // a lost packet): Segment dummySegment; unsigned numBytesRead; struct timeval presentationTime; // (this works only if the source can be read synchronously) fInputSource->syncGetNextFrame(dummySegment.buf, sizeof dummySegment.buf, numBytesRead, presentationTime); } else { break; // from while (1) } }#endif fAreEnqueueingADU = True; fSegments->enqueueNewSegment(fInputSource, this); } else { // Return a frame now: generateFrameFromHeadADU(); // sets fFrameSize, fPresentationTime, and fDurationInMicroseconds // Call our own 'after getting' function. Because we're not a 'leaf' // source, we can call this directly, without risking infinite recursion. afterGetting(this); }}Boolean MP3FromADUSource::needToGetAnADU() { // Check whether we need to first enqueue a new ADU before we // can generate a frame for our head ADU. Boolean needToEnqueue = True; if (!fSegments->isEmpty()) { unsigned index = fSegments->headIndex(); Segment* seg = &(fSegments->headSegment()); int const endOfHeadFrame = (int) seg->dataHere(); unsigned frameOffset = 0; while (1) { int endOfData = frameOffset - seg->backpointer + seg->aduSize; if (endOfData >= endOfHeadFrame) { // We already have enough data to generate a frame needToEnqueue = False; break; } frameOffset += seg->dataHere(); index = SegmentQueue::nextIndex(index); if (index == fSegments->nextFreeIndex()) break; seg = &(fSegments->s[index]); } } return needToEnqueue;}void MP3FromADUSource::insertDummyADUsIfNecessary() { if (fSegments->isEmpty()) return; // shouldn't happen // The tail segment (ADU) is assumed to have been recently // enqueued. If its backpointer would overlap the data // of the previous ADU, then we need to insert one or more // empty, 'dummy' ADUs ahead of it. (This situation should occur // only if an intermediate ADU was lost.) unsigned tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex()); Segment* tailSeg = &(fSegments->s[tailIndex]); while (1) { unsigned prevADUend; // relative to the start of the new ADU if (fSegments->headIndex() != tailIndex) { // there is a previous segment unsigned prevIndex = SegmentQueue::prevIndex(tailIndex); Segment& prevSegment = fSegments->s[prevIndex]; prevADUend = prevSegment.dataHere() + prevSegment.backpointer; if (prevSegment.aduSize > prevADUend) { // shouldn't happen if the previous ADU was well-formed prevADUend = 0; } else { prevADUend -= prevSegment.aduSize; } } else { prevADUend = 0; } if (tailSeg->backpointer > prevADUend) { // We need to insert a dummy ADU in front of the tail#ifdef DEBUG 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());#endif tailIndex = fSegments->nextFreeIndex(); if (!fSegments->insertDummyBeforeTail(prevADUend)) return; tailSeg = &(fSegments->s[tailIndex]); } else { break; // no more dummy ADUs need to be inserted } }}Boolean MP3FromADUSource::generateFrameFromHeadADU() { // Output a frame for the head ADU: if (fSegments->isEmpty()) return False; unsigned index = fSegments->headIndex(); Segment* seg = &(fSegments->headSegment());#ifdef DEBUG 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);#endif unsigned char* toPtr = fTo; // output header and side info: fFrameSize = seg->frameSize; fPresentationTime = seg->presentationTime; fDurationInMicroseconds = seg->durationInMicroseconds; memmove(toPtr, seg->dataStart(), seg->headerSize + seg->sideInfoSize); toPtr += seg->headerSize + seg->sideInfoSize; // zero out the rest of the frame, in case ADU data doesn't fill it all in unsigned bytesToZero = seg->dataHere(); for (unsigned i = 0; i < bytesToZero; ++i) { toPtr[i] = '\0'; } // Fill in the frame with appropriate ADU data from this and // subsequent ADUs: unsigned frameOffset = 0; unsigned toOffset = 0; unsigned const endOfHeadFrame = seg->dataHere(); while (toOffset < endOfHeadFrame) { int startOfData = frameOffset - seg->backpointer; if (startOfData > (int)endOfHeadFrame) break; // no more ADUs needed int endOfData = startOfData + seg->aduSize; if (endOfData > (int)endOfHeadFrame) { endOfData = endOfHeadFrame; } unsigned fromOffset; if (startOfData <= (int)toOffset) { fromOffset = toOffset - startOfData; startOfData = toOffset; if (endOfData < startOfData) endOfData = startOfData; } else { fromOffset = 0; // we may need some padding bytes beforehand unsigned bytesToZero = startOfData - toOffset;#ifdef DEBUG if (bytesToZero > 0) fprintf(stderr, "a->m:outputting %d zero bytes (%d, %d, %d, %d)\n", bytesToZero, startOfData, toOffset, frameOffset, seg->backpointer);#endif toOffset += bytesToZero; } unsigned char* fromPtr = &seg->dataStart()[seg->headerSize + seg->sideInfoSize + fromOffset]; unsigned bytesUsedHere = endOfData - startOfData;#ifdef DEBUG if (bytesUsedHere > 0) fprintf(stderr, "a->m:outputting %d bytes from %d<-%d\n", bytesUsedHere, seg->aduSize, seg->backpointer);#endif memmove(toPtr + toOffset, fromPtr, bytesUsedHere); toOffset += bytesUsedHere; frameOffset += seg->dataHere(); index = SegmentQueue::nextIndex(index); if (index == fSegments->nextFreeIndex()) break; seg = &(fSegments->s[index]); } fSegments->dequeue(); return True;}////////// Segment //////////unsigned Segment::dataHere() { int result = frameSize - (headerSize + sideInfoSize); if (result < 0) { return 0; } return (unsigned)result;} ////////// SegmentQueue //////////void SegmentQueue::enqueueNewSegment(FramedSource* inputSource, FramedSource* usingSource) { if (isFull()) { usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n"; FramedSource::handleClosure(usingSource); return; } fUsingSource = usingSource; Segment& seg = nextFreeSegment(); inputSource->getNextFrame(seg.buf, sizeof seg.buf, sqAfterGettingSegment, this, FramedSource::handleClosure, usingSource);}void SegmentQueue::sqAfterGettingSegment(void* clientData, unsigned numBytesRead, unsigned /*numTruncatedBytes*/, struct timeval presentationTime, unsigned durationInMicroseconds) { SegmentQueue* segQueue = (SegmentQueue*)clientData; Segment& seg = segQueue->nextFreeSegment(); seg.presentationTime = presentationTime; seg.durationInMicroseconds = durationInMicroseconds; if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) {#ifdef DEBUG char const* direction = segQueue->fDirectionIsToADU ? "m->a" : "a->m"; 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);#endif } // Continue our original calling source where it left off: segQueue->fUsingSource->doGetNextFrame();}// Common code called after a new segment is enqueuedBoolean SegmentQueue::sqAfterGettingCommon(Segment& seg, unsigned numBytesRead) { unsigned char* fromPtr = seg.buf; if (fIncludeADUdescriptors) { // The newly-read data is assumed to be an ADU with a descriptor // in front (void)ADUdescriptor::getRemainingFrameSize(fromPtr); seg.descriptorSize = (unsigned)(fromPtr-seg.buf); } else { seg.descriptorSize = 0; } // parse the MP3-specific info in the frame to get the ADU params unsigned hdr; MP3SideInfo sideInfo; if (!GetADUInfoFromMP3Frame(fromPtr, numBytesRead, hdr, seg.frameSize, sideInfo, seg.sideInfoSize, seg.backpointer, seg.aduSize)) { return False; } // If we've just read an ADU (rather than a regular MP3 frame), then use the // entire "numBytesRead" data for the 'aduSize', so that we include any // 'ancillary data' that may be present at the end of the ADU: if (!fDirectionIsToADU) { unsigned newADUSize = numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize; if (newADUSize > seg.aduSize) seg.aduSize = newADUSize; } fTotalDataSize += seg.dataHere(); fNextFreeIndex = nextIndex(fNextFreeIndex); return True;}Boolean SegmentQueue::dequeue() { if (isEmpty()) { fUsingSource->envir() << "SegmentQueue::dequeue(): underflow!\n"; return False; } Segment& seg = s[headIndex()]; fTotalDataSize -= seg.dataHere(); fHeadIndex = nextIndex(fHeadIndex); return True;}Boolean SegmentQueue::insertDummyBeforeTail(unsigned backpointer) { if (isEmptyOrFull()) return False; // Copy the current tail segment to its new position, then modify the // old tail segment to be a 'dummy' ADU unsigned newTailIndex = nextFreeIndex(); Segment& newTailSeg = s[newTailIndex]; unsigned oldTailIndex = prevIndex(newTailIndex); Segment& oldTailSeg = s[oldTailIndex]; newTailSeg = oldTailSeg; // structure copy // Begin by setting (replacing) the ADU descriptor of the dummy ADU: unsigned char* ptr = oldTailSeg.buf; if (fIncludeADUdescriptors) { unsigned remainingFrameSize = oldTailSeg.headerSize + oldTailSeg.sideInfoSize + 0 /* 0-size ADU */; unsigned currentDescriptorSize = oldTailSeg.descriptorSize; if (currentDescriptorSize == 2) { ADUdescriptor::generateTwoByteDescriptor(ptr, remainingFrameSize); } else { (void)ADUdescriptor::generateDescriptor(ptr, remainingFrameSize); } } // Then zero out the side info of the dummy frame: if (!ZeroOutMP3SideInfo(ptr, oldTailSeg.frameSize, backpointer)) return False; unsigned dummyNumBytesRead = oldTailSeg.descriptorSize + 4/*header size*/ + oldTailSeg.sideInfoSize; return sqAfterGettingCommon(oldTailSeg, dummyNumBytesRead);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -