📄 amraudiortpsource.cpp
字号:
// Strange TOC entry! fOurSource.envir() << "AMRBufferedPacket::nextEnclosedFrameSize(): invalid FT: " << FT << "\n"; frameSize = 0; // This probably messes up the rest of this packet, but... }#ifdef DEBUG fprintf(stderr, "AMRBufferedPacket::nextEnclosedFrameSize(): frame #: %d, FT: %d, isWideband: %d => frameSize: %d (dataSize: %d)\n", tocIndex, FT, fOurSource.isWideband(), frameSize, dataSize);#endif ++fOurSource.frameIndex(); if (dataSize < frameSize) return 0; return frameSize;}BufferedPacket* AMRBufferedPacketFactory::createNewPacket(MultiFramedRTPSource* ourSource) { return new AMRBufferedPacket((RawAMRRTPSource&)(*ourSource));}///////// AMRDeinterleavingBuffer /////////// (used to implement AMRDeinterleaver)#define AMR_MAX_FRAME_SIZE 60class AMRDeinterleavingBuffer {public: AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize); virtual ~AMRDeinterleavingBuffer(); void deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source, struct timeval presentationTime); Boolean retrieveFrame(unsigned char* to, unsigned maxSize, unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, u_int8_t& resultFrameHeader, struct timeval& resultPresentationTime); unsigned char* inputBuffer() { return fInputBuffer; } unsigned inputBufferSize() const { return AMR_MAX_FRAME_SIZE; }private: unsigned char* createNewBuffer(); class FrameDescriptor { public: FrameDescriptor(); virtual ~FrameDescriptor(); unsigned frameSize; unsigned char* frameData; u_int8_t frameHeader; struct timeval presentationTime; }; unsigned fNumChannels, fMaxInterleaveGroupSize; FrameDescriptor* fFrames[2]; unsigned char fIncomingBankId; // toggles between 0 and 1 unsigned char fIncomingBinMax; // in the incoming bank unsigned char fOutgoingBinMax; // in the outgoing bank unsigned char fNextOutgoingBin; Boolean fHaveSeenPackets; u_int16_t fLastPacketSeqNumForGroup; unsigned char* fInputBuffer; struct timeval fLastRetrievedPresentationTime;};////////// AMRDeinterleaver implementation /////////AMRDeinterleaver* AMRDeinterleaver::createNew(UsageEnvironment& env, Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize, RawAMRRTPSource* inputSource) { return new AMRDeinterleaver(env, isWideband, numChannels, maxInterleaveGroupSize, inputSource);}AMRDeinterleaver::AMRDeinterleaver(UsageEnvironment& env, Boolean isWideband, unsigned numChannels, unsigned maxInterleaveGroupSize, RawAMRRTPSource* inputSource) : AMRAudioSource(env, isWideband, numChannels), fInputSource(inputSource), fNeedAFrame(False) { fDeinterleavingBuffer = new AMRDeinterleavingBuffer(numChannels, maxInterleaveGroupSize);}AMRDeinterleaver::~AMRDeinterleaver() { delete fDeinterleavingBuffer; Medium::close(fInputSource);}static unsigned const uSecsPerFrame = 20000; // 20 msvoid AMRDeinterleaver::doGetNextFrame() { // First, try getting a frame from the deinterleaving buffer: if (fDeinterleavingBuffer->retrieveFrame(fTo, fMaxSize, fFrameSize, fNumTruncatedBytes, fLastFrameHeader, fPresentationTime)) { // Success! fNeedAFrame = False; fDurationInMicroseconds = uSecsPerFrame; // Call our own 'after getting' function. Because we're not a 'leaf' // source, we can call this directly, without risking // infinite recursion afterGetting(this); return; } // No luck, so ask our source for help: fNeedAFrame = True; if (!fInputSource->isCurrentlyAwaitingData()) { fInputSource->getNextFrame(fDeinterleavingBuffer->inputBuffer(), fDeinterleavingBuffer->inputBufferSize(), afterGettingFrame, this, FramedSource::handleClosure, this); }}void AMRDeinterleaver::afterGettingFrame(void* clientData, unsigned frameSize, unsigned /*numTruncatedBytes*/, struct timeval presentationTime, unsigned /*durationInMicroseconds*/) { AMRDeinterleaver* deinterleaver = (AMRDeinterleaver*)clientData; deinterleaver->afterGettingFrame1(frameSize, presentationTime);}void AMRDeinterleaver::afterGettingFrame1(unsigned frameSize, struct timeval presentationTime) { RawAMRRTPSource* source = (RawAMRRTPSource*)fInputSource; // First, put the frame into our deinterleaving buffer: fDeinterleavingBuffer->deliverIncomingFrame(frameSize, source, presentationTime); // Then, try delivering a frame to the client (if he wants one): if (fNeedAFrame) doGetNextFrame();}////////// AMRDeinterleavingBuffer implementation /////////AMRDeinterleavingBuffer::AMRDeinterleavingBuffer(unsigned numChannels, unsigned maxInterleaveGroupSize) : fNumChannels(numChannels), fMaxInterleaveGroupSize(maxInterleaveGroupSize), fIncomingBankId(0), fIncomingBinMax(0), fOutgoingBinMax(0), fNextOutgoingBin(0), fHaveSeenPackets(False) { // Use two banks of descriptors - one for incoming, one for outgoing fFrames[0] = new FrameDescriptor[fMaxInterleaveGroupSize]; fFrames[1] = new FrameDescriptor[fMaxInterleaveGroupSize]; fInputBuffer = createNewBuffer();}AMRDeinterleavingBuffer::~AMRDeinterleavingBuffer() { delete[] fInputBuffer; delete[] fFrames[0]; delete[] fFrames[1];}void AMRDeinterleavingBuffer::deliverIncomingFrame(unsigned frameSize, RawAMRRTPSource* source, struct timeval presentationTime) { unsigned char const ILL = source->ILL(); unsigned char const ILP = source->ILP(); unsigned frameIndex = source->frameIndex(); unsigned short packetSeqNum = source->curPacketRTPSeqNum(); // First perform a sanity check on the parameters: // (This is overkill, as the source should have already done this.) if (ILP > ILL || frameIndex == 0) {#ifdef DEBUG fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame() param sanity check failed (%d,%d,%d,%d)\n", frameSize, ILL, ILP, frameIndex);#endif exit(1); } --frameIndex; // because it was incremented by the source when this frame was read u_int8_t frameHeader; if (frameIndex >= source->TOCSize()) { // sanity check frameHeader = FT_NO_DATA<<3; } else { frameHeader = source->TOC()[frameIndex]; } unsigned frameBlockIndex = frameIndex/fNumChannels; unsigned frameWithinFrameBlock = frameIndex%fNumChannels; // The input "presentationTime" was that of the first frame-block in this // packet. Update it for the current frame: unsigned uSecIncrement = frameBlockIndex*(ILL+1)*uSecsPerFrame; presentationTime.tv_usec += uSecIncrement; presentationTime.tv_sec += presentationTime.tv_usec/1000000; presentationTime.tv_usec = presentationTime.tv_usec%1000000; // Next, check whether this packet is part of a new interleave group if (!fHaveSeenPackets || seqNumLT(fLastPacketSeqNumForGroup, packetSeqNum + frameBlockIndex)) { // We've moved to a new interleave group#ifdef DEBUG fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): new interleave group\n");#endif fHaveSeenPackets = True; fLastPacketSeqNumForGroup = packetSeqNum + ILL - ILP; // Switch the incoming and outgoing banks: fIncomingBankId ^= 1; unsigned char tmp = fIncomingBinMax; fIncomingBinMax = fOutgoingBinMax; fOutgoingBinMax = tmp; fNextOutgoingBin = 0; } // Now move the incoming frame into the appropriate bin: unsigned const binNumber = ((ILP + frameBlockIndex*(ILL+1))*fNumChannels + frameWithinFrameBlock) % fMaxInterleaveGroupSize; // the % is for sanity#ifdef DEBUG fprintf(stderr, "AMRDeinterleavingBuffer::deliverIncomingFrame(): frameIndex %d (%d,%d) put in bank %d, bin %d (%d): size %d, header 0x%02x, presentationTime %lu.%06ld\n", frameIndex, frameBlockIndex, frameWithinFrameBlock, fIncomingBankId, binNumber, fMaxInterleaveGroupSize, frameSize, frameHeader, presentationTime.tv_sec, presentationTime.tv_usec);#endif FrameDescriptor& inBin = fFrames[fIncomingBankId][binNumber]; unsigned char* curBuffer = inBin.frameData; inBin.frameData = fInputBuffer; inBin.frameSize = frameSize; inBin.frameHeader = frameHeader; inBin.presentationTime = presentationTime; if (curBuffer == NULL) curBuffer = createNewBuffer(); fInputBuffer = curBuffer; if (binNumber >= fIncomingBinMax) { fIncomingBinMax = binNumber + 1; }}Boolean AMRDeinterleavingBuffer::retrieveFrame(unsigned char* to, unsigned maxSize, unsigned& resultFrameSize, unsigned& resultNumTruncatedBytes, u_int8_t& resultFrameHeader, struct timeval& resultPresentationTime) { if (fNextOutgoingBin >= fOutgoingBinMax) return False; // none left FrameDescriptor& outBin = fFrames[fIncomingBankId^1][fNextOutgoingBin]; unsigned char* fromPtr = outBin.frameData; unsigned char fromSize = outBin.frameSize; outBin.frameSize = 0; // for the next time this bin is used // Check whether this frame is missing; if so, return a FT_NO_DATA frame: if (fromSize == 0) { resultFrameHeader = FT_NO_DATA<<3; // Compute this erasure frame's presentation time via extrapolation: resultPresentationTime = fLastRetrievedPresentationTime; resultPresentationTime.tv_usec += uSecsPerFrame; if (resultPresentationTime.tv_usec >= 1000000) { ++resultPresentationTime.tv_sec; resultPresentationTime.tv_usec -= 1000000; } } else { // Normal case - a frame exists: resultFrameHeader = outBin.frameHeader; resultPresentationTime = outBin.presentationTime; } fLastRetrievedPresentationTime = resultPresentationTime; if (fromSize > maxSize) { resultNumTruncatedBytes = fromSize - maxSize; resultFrameSize = maxSize; } else { resultNumTruncatedBytes = 0; resultFrameSize = fromSize; } memmove(to, fromPtr, resultFrameSize);#ifdef DEBUG fprintf(stderr, "AMRDeinterleavingBuffer::retrieveFrame(): from bank %d, bin %d: size %d, header 0x%02x, presentationTime %lu.%06ld\n", fIncomingBankId^1, fNextOutgoingBin, resultFrameSize, resultFrameHeader, resultPresentationTime.tv_sec, resultPresentationTime.tv_usec);#endif ++fNextOutgoingBin; return True;}unsigned char* AMRDeinterleavingBuffer::createNewBuffer() { return new unsigned char[inputBufferSize()];}AMRDeinterleavingBuffer::FrameDescriptor::FrameDescriptor() : frameSize(0), frameData(NULL) {}AMRDeinterleavingBuffer::FrameDescriptor::~FrameDescriptor() { delete[] frameData;}// Unpack bandwidth-aligned data to octet-aligned:static unsigned short frameBitsFromFT[16] = { 95, 103, 118, 134, 148, 159, 204, 244, 39, 0, 0, 0, 0, 0, 0, 0};static unsigned short frameBitsFromFTWideband[16] = { 132, 177, 253, 285, 317, 365, 397, 461, 477, 40, 0, 0, 0, 0, 0, 0};static void unpackBandwidthEfficientData(BufferedPacket* packet, Boolean isWideband) {#ifdef DEBUG fprintf(stderr, "Unpacking 'bandwidth-efficient' payload (%d bytes):\n", packet->dataSize()); for (unsigned j = 0; j < packet->dataSize(); ++j) { fprintf(stderr, "%02x:", (packet->data())[j]); } fprintf(stderr, "\n");#endif BitVector fromBV(packet->data(), 0, 8*packet->dataSize()); unsigned const toBufferSize = 2*packet->dataSize(); // conservatively large unsigned char* toBuffer = new unsigned char[toBufferSize]; unsigned toCount = 0; // Begin with the payload header: unsigned CMR = fromBV.getBits(4); toBuffer[toCount++] = CMR << 4; // Then, run through and unpack the TOC entries: while (1) { unsigned toc = fromBV.getBits(6); toBuffer[toCount++] = toc << 2; if ((toc&0x20) == 0) break; // the F bit is 0 } // Then, using the TOC data, unpack each frame payload: unsigned const tocSize = toCount - 1; for (unsigned i = 1; i <= tocSize; ++i) { unsigned char tocByte = toBuffer[i]; unsigned char const FT = (tocByte&0x78) >> 3; unsigned short frameSizeBits = isWideband ? frameBitsFromFTWideband[FT] : frameBitsFromFT[FT]; unsigned short frameSizeBytes = (frameSizeBits+7)/8; shiftBits(&toBuffer[toCount], 0, // to packet->data(), fromBV.curBitIndex(), // from frameSizeBits // num bits );#ifdef DEBUG if (frameSizeBits > fromBV.numBitsRemaining()) { fprintf(stderr, "\tWarning: Unpacking frame %d of %d: want %d bits, but only %d are available!\n", i, tocSize, frameSizeBits, fromBV.numBitsRemaining()); }#endif fromBV.skipBits(frameSizeBits); toCount += frameSizeBytes; } #ifdef DEBUG if (fromBV.numBitsRemaining() > 7) { fprintf(stderr, "\tWarning: %d bits remain unused!\n", fromBV.numBitsRemaining()); }#endif // Finally, replace the current packet data with the unpacked data: packet->removePadding(packet->dataSize()); // throws away current packet data packet->appendData(toBuffer, toCount); delete[] toBuffer;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -