RFC3199定义了MP3的RTP打包规则。首先来看看处理*.mp3的sesseion是如何创建的
static ServerMediaSession* createNewSMS(UsageEnvironment& env,
char const* fileName, FILE* /*fid*/) {
...
else if (strcmp(extension, ".mp3") == 0) {
// Assumed to be a MPEG-1 or 2 Audio file:
NEW_SMS("MPEG-1 or 2 Audio");
//去注释STREAM_USING_ADUS宏,传输时使用ADUs,而不是MP3裸帧
// To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:
//#define STREAM_USING_ADUS 1
//去注释INTERLEAVE_ADUS宏,在传输之前奖ADUs重排序(交错)
// To also reorder ADUs before streaming, uncomment the following:
//#define INTERLEAVE_ADUS 1
// (For more information about ADUs and interleaving,
// see )
Boolean useADUs = False;
Interleaving* interleaving = NULL;
#ifdef STREAM_USING_ADUS
useADUs = True;
#ifdef INTERLEAVE_ADUS
unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...
unsigned const interleaveCycleSize
= (sizeof interleaveCycle)/(sizeof (unsigned char));
interleaving = new Interleaving(interleaveCycleSize, interleaveCycle); //创建一个用于交错的filter
#endif
#endif
sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving)); //注意这里传递的参数
}
}
FramedSource* MP3AudioFileServerMediaSubsession
::createNewStreamSourceCommon(FramedSource* baseMP3Source, unsigned mp3NumBytes, unsigned& estBitrate) {
FramedSource* streamSource;
fFileDuration = 0.0;
do {
streamSource = baseMP3Source; // by default
if (streamSource == NULL) break;
// Use the MP3 file size, plus the duration, to estimate the stream's bitrate:
if (mp3NumBytes > 0 && fFileDuration > 0.0) {
estBitrate = (unsigned)(mp3NumBytes/(125*fFileDuration) + 0.5); // kbps, rounded
} else {
estBitrate = 128; // kbps, estimate
}
if (fGenerateADUs) { //判断是否打包成ADU后发送
// Add a filter that converts the source MP3s to ADUs:
streamSource = ADUFromMP3Source::createNew(envir(), streamSource);
if (streamSource == NULL) break;
if (fInterleaving != NULL) {
// Add another filter that interleaves the ADUs before packetizing:
streamSource = MP3ADUinterleaver::createNew(envir(), *fInterleaving,
streamSource);
if (streamSource == NULL) break;
}
} else if (fFileDuration > 0.0) {
//
//注意了,对于不需要打包成ADU的情况,这里有一个打包再解包的过程,为是的方便定位
//
// Because this is a seekable file, insert a pair of filters: one that
// converts the input MP3 stream to ADUs; another that converts these
// ADUs back to MP3. This allows us to seek within the input stream without
// tripping over the MP3 'bit reservoir':
streamSource = ADUFromMP3Source::createNew(envir(), streamSource);
if (streamSource == NULL) break;
streamSource = MP3FromADUSource::createNew(envir(), streamSource);
if (streamSource == NULL) break;
}
} while (0);
return streamSource; //返回的是最外层的source
}
void ADUFromMP3Source::doGetNextFrame() {
if (!fAreEnqueueingMP3Frame) { //分支1
// Arrange to enqueue a new MP3 frame:
fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize();
fAreEnqueueingMP3Frame = True;
fSegments->enqueueNewSegment(fInputSource, this);
} else { //分支2
// Deliver an ADU from a previously-read MP3 frame:
fAreEnqueueingMP3Frame = False;
if (!doGetNextFrame1()) {
// An internal error occurred; act as if our source went away:
FramedSource::handleClosure(this);
}
}
}
void SegmentQueue::enqueueNewSegment(FramedSource* inputSource,
FramedSource* usingSource) {
if (isFull()) {
usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n";
FramedSource::handleClosure(usingSource);
return;
}
fUsingSource = usingSource;
Segment& seg = nextFreeSegment();
//从source获取mp3数据
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(); //获取刚才读入数据的segment
seg.presentationTime = presentationTime;
seg.durationInMicroseconds = durationInMicroseconds;
if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) { //分析读取到的mp3 frame
#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(); //又一次调用了doGetNextFrame函数
}
// Common code called after a new segment is enqueued
Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,
unsigned numBytesRead) {
unsigned char* fromPtr = seg.buf;
//是否已经包含了ADU标识
if (fIncludeADUdescriptors) { //对ADUFromMP3Source中的SegmentQueue,这个值必然为False
// The newly-read data is assumed to be an ADU with a descriptor
// in front
//
//getRemainingFrameSize中根据fromPtr第1个字节决定了descriptor为1个或者两个字节
//
(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; //4字节的frame头
MP3SideInfo sideInfo; //side info
//分析frame,获取相关信息
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) { //默认值为True
unsigned newADUSize
= numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize;
if (newADUSize > seg.aduSize) seg.aduSize = newADUSize;
}
fTotalDataSize += seg.dataHere();
fNextFreeIndex = nextIndex(fNextFreeIndex); //更新空闲segment索引
return True;
}
Boolean GetADUInfoFromMP3Frame(unsigned char const* framePtr,
unsigned totFrameSize,
unsigned& hdr, unsigned& frameSize,
MP3SideInfo& sideInfo, unsigned& sideInfoSize,
unsigned& backpointer, unsigned& aduSize) {
if (totFrameSize < 4) return False; // there's not enough data
MP3FrameParams fr; //MP3FrameParams类专门用来分析mp3帧信息
//前4个字节是mp3的帧头
fr.hdr = ((unsigned)framePtr[0] << 24) | ((unsigned)framePtr[1] << 16)
| ((unsigned)framePtr[2] << 8) | (unsigned)framePtr[3];
fr.setParamsFromHeader(); //分析4字节头部
fr.setBytePointer(framePtr + 4, totFrameSize - 4); // skip hdr
frameSize = 4 + fr.frameSize;
//非mp3帧(mp2或者mp1)
if (fr.layer != 3) {
// Special case for non-layer III frames
backpointer = 0;
sideInfoSize = 0;
aduSize = fr.frameSize;
return True;
}
sideInfoSize = fr.sideInfoSize;
if (totFrameSize < 4 + sideInfoSize) return False; // not enough data
fr.getSideInfo(sideInfo);
hdr = fr.hdr; //4字节头
backpointer = sideInfo.main_data_begin; //数据开始位置
unsigned numBits = sideInfo.ch[0].gr[0].part2_3_length;
numBits += sideInfo.ch[0].gr[1].part2_3_length;
numBits += sideInfo.ch[1].gr[0].part2_3_length;
numBits += sideInfo.ch[1].gr[1].part2_3_length;
aduSize = (numBits+7)/8; //adu字节数
#ifdef DEBUG
fprintf(stderr, "mp3GetADUInfoFromFrame: hdr: %08x, frameSize: %d, part2_3_lengths: %d,%d,%d,%d, aduSize: %d, backpointer: %d\n", hdr, frameSize, sideInfo.ch[0].gr[0].part2_3_length, sideInfo.ch[0].gr[1].part2_3_length, sideInfo.ch[1].gr[0].part2_3_length, sideInfo.ch[1].gr[1].part2_3_length, aduSize, backpointer);
#endif
return True;
}
void MP3FrameParams::setParamsFromHeader() {
if (hdr & (1<<20)) {
isMPEG2 = (hdr & (1<<19)) ? 0x0 : 0x1;
isMPEG2_5 = 0;
}
else {
isMPEG2 = 1;
isMPEG2_5 = 1;
}
layer = 4-((hdr>>17)&3);
if (layer == 4) layer = 3; // layer==4 is not allowed
bitrateIndex = ((hdr>>12)&0xf);
if (isMPEG2_5) {
samplingFreqIndex = ((hdr>>10)&0x3) + 6;
} else {
samplingFreqIndex = ((hdr>>10)&0x3) + (isMPEG2*3);
}
hasCRC = ((hdr>>16)&0x1)^0x1;
padding = ((hdr>>9)&0x1);
extension = ((hdr>>8)&0x1);
mode = ((hdr>>6)&0x3);
mode_ext = ((hdr>>4)&0x3);
copyright = ((hdr>>3)&0x1);
original = ((hdr>>2)&0x1);
emphasis = hdr & 0x3;
stereo = (mode == MPG_MD_MONO) ? 1 : 2;
if (((hdr>>10)&0x3) == 0x3) {
#ifdef DEBUG_ERRORS
fprintf(stderr,"Stream error - hdr: 0x%08x\n", hdr);
#endif
}
bitrate = live_tabsel[isMPEG2][layer-1][bitrateIndex];
samplingFreq = live_freqs[samplingFreqIndex];
isStereo = (stereo > 1);
isFreeFormat = (bitrateIndex == 0);
frameSize
= ComputeFrameSize(bitrate, samplingFreq, padding, isMPEG2, layer); //计算frame的大小
sideInfoSize = computeSideInfoSize();
}
unsigned ComputeFrameSize(unsigned bitrate, unsigned samplingFreq,
Boolean usePadding, Boolean isMPEG2,
unsigned char layer) {
if (samplingFreq == 0) return 0;
unsigned const bitrateMultiplier = (layer == 1) ? 12000*4 : 144000;
unsigned framesize;
framesize = bitrate*bitrateMultiplier;
framesize /= samplingFreq<
Boolean ADUFromMP3Source::doGetNextFrame1() {
// First, check whether we have enough previously-read data to output an
// ADU for the last-read MP3 frame:
unsigned tailIndex;
Segment* tailSeg;
Boolean needMoreData;
if (fSegments->isEmpty()) {
needMoreData = True;
tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings
} else {
tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex()); //获取上一个填充了数据的segment
tailSeg = &(fSegments->s[tailIndex]);
needMoreData
= fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far
|| tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data
}
if (needMoreData) { //
// We don't have enough data to output an ADU from the last-read MP3
// frame, so need to read another one and try again:
doGetNextFrame(); //没有足够的数据,则重新读取数据
return True;
}
//从尾部的segment中获取一个ADU
// Output an ADU from the tail segment:
fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize;
fPresentationTime = tailSeg->presentationTime;
fDurationInMicroseconds = tailSeg->durationInMicroseconds;
unsigned descriptorSize
= fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0;
if (descriptorSize + fFrameSize > fMaxSize) {
envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room ("
<< descriptorSize + fFrameSize << ">"
<< fMaxSize << ")\n";
fFrameSize = 0;
return False;
}
unsigned char* toPtr = fTo;
//输出ADU描述符
// output the ADU descriptor:
if (fIncludeADUdescriptors) { //默认值为False
fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize);
}
//输出header和side info
// output header and side info:
memmove(toPtr, tailSeg->dataStart(),
tailSeg->headerSize + tailSeg->sideInfoSize);
toPtr += tailSeg->headerSize + tailSeg->sideInfoSize;
//输出数据
// go back to the frame that contains the start of our data:
unsigned offset = 0;
unsigned i = tailIndex;
unsigned prevBytes = tailSeg->backpointer;
while (prevBytes > 0) {
i = SegmentQueue::prevIndex(i);
unsigned dataHere = fSegments->s[i].dataHere();
if (dataHere < prevBytes) {
prevBytes -= dataHere;
} else {
offset = dataHere - prevBytes;
break;
}
}
// dequeue any segments that we no longer need:
while (fSegments->headIndex() != i) {
fSegments->dequeue(); // we're done with it
}
unsigned bytesToUse = tailSeg->aduSize;
while (bytesToUse > 0) {
Segment& seg = fSegments->s[i];
unsigned char* fromPtr
= &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset];
unsigned dataHere = seg.dataHere() - offset;
unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse;
memmove(toPtr, fromPtr, bytesUsedHere);
bytesToUse -= bytesUsedHere;
toPtr += bytesUsedHere;
offset = 0;
i = SegmentQueue::nextIndex(i);
}
if (fFrameCounter++%fScale == 0) { //快进快退操作,丢弃不需要的帧
// Call our own 'after getting' function. Because we're not a 'leaf'
// source, we can call this directly, without risking infinite recursion.
afterGetting(this);
} else {
// Don't use this frame; get another one:
doGetNextFrame();
}
return True;
}