live555源码分析----关于mp3的处理

转载 :http://blog.csdn.net/gavinr/article/details/7186627


RFC3199定义了MP3的RTP打包规则。首先来看看处理*.mp3的sesseion是如何创建的

  1. static ServerMediaSession* createNewSMS(UsageEnvironment& env,  
  2.                     char const* fileName, FILE/*fid*/) {  
  3. ...  
  4.    else if (strcmp(extension, ".mp3") == 0) {  
  5.     // Assumed to be a MPEG-1 or 2 Audio file:  
  6.     NEW_SMS("MPEG-1 or 2 Audio");  
  7.   
  8.   
  9.     //去注释STREAM_USING_ADUS宏,传输时使用ADUs,而不是MP3裸帧  
  10.     // To stream using 'ADUs' rather than raw MP3 frames, uncomment the following:  
  11. //#define STREAM_USING_ADUS 1  
  12.     //去注释INTERLEAVE_ADUS宏,在传输之前奖ADUs重排序(交错)  
  13.     // To also reorder ADUs before streaming, uncomment the following:  
  14. //#define INTERLEAVE_ADUS 1  
  15.     // (For more information about ADUs and interleaving,  
  16.     //  see <http://www.live555.com/rtp-mp3/>)  
  17.     Boolean useADUs = False;  
  18.     Interleaving* interleaving = NULL;  
  19. #ifdef STREAM_USING_ADUS  
  20.     useADUs = True;  
  21. #ifdef INTERLEAVE_ADUS  
  22.     unsigned char interleaveCycle[] = {0,2,1,3}; // or choose your own...  
  23.     unsigned const interleaveCycleSize  
  24.       = (sizeof interleaveCycle)/(sizeof (unsigned char));  
  25.     interleaving = new Interleaving(interleaveCycleSize, interleaveCycle);  //创建一个用于交错的filter  
  26. #endif  
  27. #endif  
  28.     sms->addSubsession(MP3AudioFileServerMediaSubsession::createNew(env, fileName, reuseSource, useADUs, interleaving)); //注意这里传递的参数  
  29.   
  30.   
  31.   }  
  32. }  

    上面的代码打开宏STREAM_USING_ADUS,则会将MP3帧打包成ADU后,再发送。打开宏INTERLEAVE_ADUS,MP3打包成ADU后,将进行交错排列。可以看到默认情况下,这两个选项都是关闭的。在MP3AudioFileServerMediaSubsession::createNewStreamSource函数中会调用一个createNewStreamSourceCommon函数,处理ADU的打包操作。


  1. FramedSource* MP3AudioFileServerMediaSubsession  
  2. ::createNewStreamSourceCommon(FramedSource* baseMP3Source, unsigned mp3NumBytes, unsigned& estBitrate) {  
  3.   FramedSource* streamSource;  
  4.   fFileDuration = 0.0;  
  5.   do {  
  6.     streamSource = baseMP3Source; // by default  
  7.     if (streamSource == NULL) break;  
  8.   
  9.   
  10.     // Use the MP3 file size, plus the duration, to estimate the stream's bitrate:  
  11.     if (mp3NumBytes > 0 && fFileDuration > 0.0) {  
  12.       estBitrate = (unsigned)(mp3NumBytes/(125*fFileDuration) + 0.5); // kbps, rounded  
  13.     } else {  
  14.       estBitrate = 128; // kbps, estimate  
  15.     }  
  16.   
  17.   
  18.     if (fGenerateADUs) {  //判断是否打包成ADU后发送  
  19.       // Add a filter that converts the source MP3s to ADUs:  
  20.       streamSource = ADUFromMP3Source::createNew(envir(), streamSource);  
  21.       if (streamSource == NULL) break;  
  22.   
  23.   
  24.       if (fInterleaving != NULL) {  
  25.     // Add another filter that interleaves the ADUs before packetizing:  
  26.     streamSource = MP3ADUinterleaver::createNew(envir(), *fInterleaving,  
  27.                             streamSource);  
  28.     if (streamSource == NULL) break;  
  29.       }  
  30.     } else if (fFileDuration > 0.0) {     
  31.         //  
  32.         //注意了,对于不需要打包成ADU的情况,这里有一个打包再解包的过程,为是的方便定位  
  33.         //  
  34.       // Because this is a seekable file, insert a pair of filters: one that  
  35.       // converts the input MP3 stream to ADUs; another that converts these  
  36.       // ADUs back to MP3.  This allows us to seek within the input stream without  
  37.       // tripping over the MP3 'bit reservoir':  
  38.       streamSource = ADUFromMP3Source::createNew(envir(), streamSource);  
  39.       if (streamSource == NULL) break;  
  40.   
  41.   
  42.       streamSource = MP3FromADUSource::createNew(envir(), streamSource);  
  43.       if (streamSource == NULL) break;  
  44.     }  
  45.   } while (0);  
  46.   
  47.   
  48.   return streamSource;  //返回的是最外层的source  
  49. }  




    上面的代码处理了两种情况:一是根据fGenerateADUs的值决定是否生成ADU后再发送,二是对于不需要打包成ADU的情况,这里有一个打包再解包的过程,为是的方便定位。   下面来看ADU的打包过程


  1. void ADUFromMP3Source::doGetNextFrame() {  
  2.   if (!fAreEnqueueingMP3Frame) {    //分支1  
  3.     // Arrange to enqueue a new MP3 frame:  
  4.     fTotalDataSizeBeforePreviousRead = fSegments->totalDataSize();  
  5.     fAreEnqueueingMP3Frame = True;  
  6.     fSegments->enqueueNewSegment(fInputSource, this);  
  7.   } else {  //分支2  
  8.     // Deliver an ADU from a previously-read MP3 frame:  
  9.     fAreEnqueueingMP3Frame = False;  
  10.   
  11.   
  12.     if (!doGetNextFrame1()) {  
  13.       // An internal error occurred; act as if our source went away:  
  14.       FramedSource::handleClosure(this);  
  15.     }  
  16.   }  
  17. }  


    fAreEnqueueingMP3Frame初始直为False, 首先会执行第1个分支。从后面的分析中,我们会发现fSegments->enqueueNewSegmen函数最后又调用了ADUFromMP3Source::doGetNextFrame函数,这时将执行第二个分支。


  1. void SegmentQueue::enqueueNewSegment(FramedSource* inputSource,  
  2.                      FramedSource* usingSource) {  
  3.   if (isFull()) {  
  4.     usingSource->envir() << "SegmentQueue::enqueueNewSegment() overflow\n";  
  5.     FramedSource::handleClosure(usingSource);  
  6.     return;  
  7.   }  
  8.   
  9.   
  10.   fUsingSource = usingSource;  
  11.   
  12.   
  13.   Segment& seg = nextFreeSegment();  
  14.       
  15. //从source获取mp3数据  
  16.   inputSource->getNextFrame(seg.buf, sizeof seg.buf,  
  17.                 sqAfterGettingSegment, this,  
  18.                 FramedSource::handleClosure, usingSource);  
  19. }  

从source中获取mp3数据的过程就不关注了,直接看sqAfterGettingSegment函数的处理

  1. void SegmentQueue::sqAfterGettingSegment(void* clientData,  
  2.                      unsigned numBytesRead,  
  3.                      unsigned /*numTruncatedBytes*/,  
  4.                      struct timeval presentationTime,  
  5.                      unsigned durationInMicroseconds) {  
  6.   SegmentQueue* segQueue = (SegmentQueue*)clientData;  
  7.   Segment& seg = segQueue->nextFreeSegment();       //获取刚才读入数据的segment  
  8.   
  9.   
  10.   seg.presentationTime = presentationTime;  
  11.   seg.durationInMicroseconds = durationInMicroseconds;  
  12.   
  13.   
  14.   if (segQueue->sqAfterGettingCommon(seg, numBytesRead)) {  //分析读取到的mp3 frame  
  15. #ifdef DEBUG  
  16.     char const* direction = segQueue->fDirectionIsToADU ? "m->a" : "a->m";  
  17.     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);  
  18. #endif  
  19.   }  
  20.   
  21.   
  22.   // Continue our original calling source where it left off:  
  23.   segQueue->fUsingSource->doGetNextFrame();  //又一次调用了doGetNextFrame函数  
  24. }  

    获取到的数据存储在segment中,先调用sqAfterGettingCommon函数对frame进行分析。最后又一次调用了ADUFromMP3Source::doGetNextFrame函数,只不过这次将会执行第2个分支。先来看看sqAfterGettingCommon函数的细节。


  1. // Common code called after a new segment is enqueued  
  2. Boolean SegmentQueue::sqAfterGettingCommon(Segment& seg,  
  3.                        unsigned numBytesRead) {  
  4.   unsigned char* fromPtr = seg.buf;  
  5.   
  6.   
  7. //是否已经包含了ADU标识  
  8.   if (fIncludeADUdescriptors) {  //对ADUFromMP3Source中的SegmentQueue,这个值必然为False  
  9.     // The newly-read data is assumed to be an ADU with a descriptor  
  10.     // in front  
  11.     //  
  12.     //getRemainingFrameSize中根据fromPtr第1个字节决定了descriptor为1个或者两个字节  
  13.     //  
  14.     (void)ADUdescriptor::getRemainingFrameSize(fromPtr);   
  15.     seg.descriptorSize = (unsigned)(fromPtr-seg.buf);  
  16.   } else {  
  17.     seg.descriptorSize = 0;  
  18.   }  
  19.   
  20.   
  21.   
  22.   
  23.   // parse the MP3-specific info in the frame to get the ADU params  
  24.   unsigned hdr;  //4字节的frame头  
  25.   MP3SideInfo sideInfo;  //side info  
  26.   
  27.   
  28.     //分析frame,获取相关信息  
  29.   if (!GetADUInfoFromMP3Frame(fromPtr, numBytesRead,  
  30.                   hdr, seg.frameSize,  
  31.                   sideInfo, seg.sideInfoSize,  
  32.                   seg.backpointer, seg.aduSize)) {  
  33.     return False;  
  34.   }  
  35.   
  36.   
  37.   // If we've just read an ADU (rather than a regular MP3 frame), then use the  
  38.   // entire "numBytesRead" data for the 'aduSize', so that we include any  
  39.   // 'ancillary data' that may be present at the end of the ADU:  
  40.   if (!fDirectionIsToADU) { //默认值为True  
  41.     unsigned newADUSize  
  42.       = numBytesRead - seg.descriptorSize - 4/*header size*/ - seg.sideInfoSize;  
  43.     if (newADUSize > seg.aduSize) seg.aduSize = newADUSize;  
  44.   }  
  45.   fTotalDataSize += seg.dataHere();  
  46.   fNextFreeIndex = nextIndex(fNextFreeIndex);   //更新空闲segment索引  
  47.   
  48.   
  49.   return True;  
  50. }  


上面代码中的fIncludeADUdescriptors变量,表示读入到segment中的数据是否包含ADU标识符,显然ADUFromMP3Source处理的原始数据肯定是不包含ADU标识符的。

GetADUInfoFromMP3Frame函数从mp3帧中获取ADU相关的信息


  1. Boolean GetADUInfoFromMP3Frame(unsigned char const* framePtr,  
  2.                    unsigned totFrameSize,  
  3.                    unsigned& hdr, unsigned& frameSize,  
  4.                    MP3SideInfo& sideInfo, unsigned& sideInfoSize,  
  5.                    unsigned& backpointer, unsigned& aduSize) {  
  6.   if (totFrameSize < 4) return False; // there's not enough data  
  7.   
  8.   
  9.   MP3FrameParams fr;    //MP3FrameParams类专门用来分析mp3帧信息  
  10.   //前4个字节是mp3的帧头  
  11.   fr.hdr =   ((unsigned)framePtr[0] << 24) | ((unsigned)framePtr[1] << 16)  
  12.            | ((unsigned)framePtr[2] << 8) | (unsigned)framePtr[3];  
  13.   fr.setParamsFromHeader(); //分析4字节头部  
  14.   fr.setBytePointer(framePtr + 4, totFrameSize - 4); // skip hdr  
  15.   
  16.   
  17.   frameSize = 4 + fr.frameSize;  
  18.   
  19.   
  20.     //非mp3帧(mp2或者mp1)  
  21.   if (fr.layer != 3) {  
  22.     // Special case for non-layer III frames  
  23.     backpointer = 0;  
  24.     sideInfoSize = 0;  
  25.     aduSize = fr.frameSize;  
  26.     return True;  
  27.   }  
  28.   
  29.   
  30.   sideInfoSize = fr.sideInfoSize;  
  31.   if (totFrameSize < 4 + sideInfoSize) return False; // not enough data  
  32.   
  33.   
  34.   fr.getSideInfo(sideInfo);  
  35.   
  36.   
  37.   hdr = fr.hdr;  //4字节头  
  38.   backpointer = sideInfo.main_data_begin;  //数据开始位置  
  39.   unsigned numBits = sideInfo.ch[0].gr[0].part2_3_length;  
  40.   numBits += sideInfo.ch[0].gr[1].part2_3_length;  
  41.   numBits += sideInfo.ch[1].gr[0].part2_3_length;  
  42.   numBits += sideInfo.ch[1].gr[1].part2_3_length;  
  43.   aduSize = (numBits+7)/8;  //adu字节数  
  44. #ifdef DEBUG  
  45.   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);  
  46. #endif  
  47.   
  48.   
  49.   return True;  
  50. }  



来看MP3 frame头的分析
  1. void MP3FrameParams::setParamsFromHeader() {  
  2.   if (hdr & (1<<20)) {  
  3.     isMPEG2 = (hdr & (1<<19)) ? 0x0 : 0x1;  
  4.     isMPEG2_5 = 0;  
  5.   }  
  6.   else {  
  7.     isMPEG2 = 1;  
  8.     isMPEG2_5 = 1;  
  9.   }  
  10.   
  11.   
  12.   layer = 4-((hdr>>17)&3);  
  13.   if (layer == 4) layer = 3; // layer==4 is not allowed  
  14.   bitrateIndex = ((hdr>>12)&0xf);  
  15.   
  16.   
  17.   if (isMPEG2_5) {  
  18.     samplingFreqIndex = ((hdr>>10)&0x3) + 6;  
  19.   } else {  
  20.     samplingFreqIndex = ((hdr>>10)&0x3) + (isMPEG2*3);  
  21.   }  
  22.   
  23.   
  24.   hasCRC = ((hdr>>16)&0x1)^0x1;  
  25.   
  26.   
  27.   padding   = ((hdr>>9)&0x1);  
  28.   extension = ((hdr>>8)&0x1);  
  29.   mode      = ((hdr>>6)&0x3);  
  30.   mode_ext  = ((hdr>>4)&0x3);  
  31.   copyright = ((hdr>>3)&0x1);  
  32.   original  = ((hdr>>2)&0x1);  
  33.   emphasis  = hdr & 0x3;  
  34.   
  35.   
  36.   stereo    = (mode == MPG_MD_MONO) ? 1 : 2;  
  37.   
  38.   
  39.   if (((hdr>>10)&0x3) == 0x3) {  
  40. #ifdef DEBUG_ERRORS  
  41.     fprintf(stderr,"Stream error - hdr: 0x%08x\n", hdr);  
  42. #endif  
  43.   }  
  44.   
  45.   
  46.   bitrate = live_tabsel[isMPEG2][layer-1][bitrateIndex];  
  47.   samplingFreq = live_freqs[samplingFreqIndex];  
  48.   isStereo = (stereo > 1);  
  49.   isFreeFormat = (bitrateIndex == 0);  
  50.   frameSize  
  51.     = ComputeFrameSize(bitrate, samplingFreq, padding, isMPEG2, layer); //计算frame的大小  
  52.   sideInfoSize = computeSideInfoSize();  
  53.  }  

标准的mp3 frame(立体声不带CRC), 附加信息大小32位
frameSize的计算方式
  1. unsigned ComputeFrameSize(unsigned bitrate, unsigned samplingFreq,  
  2.               Boolean usePadding, Boolean isMPEG2,  
  3.               unsigned char layer) {  
  4.   if (samplingFreq == 0) return 0;  
  5.   unsigned const bitrateMultiplier = (layer == 1) ? 12000*4 : 144000;  
  6.   unsigned framesize;  
  7.   
  8.   
  9.   framesize = bitrate*bitrateMultiplier;  
  10.   framesize /= samplingFreq<<isMPEG2;  
  11.   framesize = framesize + usePadding - 4;  
  12.   
  13.   
  14.   return framesize;  
  15. }  


这里的bitrate单位为kbps
MP3帧长取决于位率和频率,计算公式为:
. mpeg1.0 layer1 : 帧长= (48000*bitrate)/sampling_freq + padding
layer2&3: 帧长= (144000*bitrate)/sampling_freq + padding
. mpeg2.0 layer1 : 帧长= (24000*bitrate)/sampling_freq + padding
layer2&3 : 帧长= (72000*bitrate)/sampling_freq + padding
根据公式,位率为128kbps,采样频率为44.1kHz,padding(帧长调节)为0时,帧长为417字节。

奇怪的是,padding为0,最后几个bit不是丢弃掉了吗?

到此,ADUFromMP3Source::doGetNextFrame()函数第1个分支分析完了,现在来看其第2个分支。分支2主要调用了ADUFromMP3Source::doGetNextFrame1函数。


  1. Boolean ADUFromMP3Source::doGetNextFrame1() {  
  2.   // First, check whether we have enough previously-read data to output an  
  3.   // ADU for the last-read MP3 frame:  
  4.   unsigned tailIndex;  
  5.   Segment* tailSeg;  
  6.   Boolean needMoreData;  
  7.   
  8.   
  9.   if (fSegments->isEmpty()) {  
  10.     needMoreData = True;  
  11.     tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings  
  12.   } else {  
  13.     tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex());  //获取上一个填充了数据的segment  
  14.     tailSeg = &(fSegments->s[tailIndex]);  
  15.   
  16.   
  17.     needMoreData  
  18.       = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far  
  19.       || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data  
  20.   }  
  21.   
  22.   
  23.   if (needMoreData) {  //  
  24.     // We don't have enough data to output an ADU from the last-read MP3  
  25.     // frame, so need to read another one and try again:  
  26.     doGetNextFrame();  //没有足够的数据,则重新读取数据  
  27.     return True;  
  28.   }  
  29.   
  30.   
  31.   //从尾部的segment中获取一个ADU  
  32.   // Output an ADU from the tail segment:  
  33.   fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize;  
  34.   fPresentationTime = tailSeg->presentationTime;  
  35.   fDurationInMicroseconds = tailSeg->durationInMicroseconds;  
  36.   unsigned descriptorSize  
  37.     = fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0;  
  38.   
  39.   
  40.   if (descriptorSize + fFrameSize > fMaxSize) {  
  41.     envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room ("  
  42.         << descriptorSize + fFrameSize << ">"  
  43.         << fMaxSize << ")\n";  
  44.     fFrameSize = 0;  
  45.     return False;  
  46.   }  
  47.   
  48.   
  49.   unsigned char* toPtr = fTo;  
  50.   
  51.   
  52.  //输出ADU描述符  
  53.   // output the ADU descriptor:  
  54.   if (fIncludeADUdescriptors) {  //默认值为False  
  55.     fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize);   
  56.   }  
  57.   
  58.   
  59.   //输出header和side info  
  60.   // output header and side info:  
  61.   memmove(toPtr, tailSeg->dataStart(),  
  62.       tailSeg->headerSize + tailSeg->sideInfoSize);  
  63.   toPtr += tailSeg->headerSize + tailSeg->sideInfoSize;  
  64.   
  65.   
  66.   //输出数据  
  67.   // go back to the frame that contains the start of our data:  
  68.   unsigned offset = 0;  
  69.   unsigned i = tailIndex;  
  70.   unsigned prevBytes = tailSeg->backpointer;  
  71.   while (prevBytes > 0) {  
  72.     i = SegmentQueue::prevIndex(i);  
  73.     unsigned dataHere = fSegments->s[i].dataHere();  
  74.     if (dataHere < prevBytes) {  
  75.       prevBytes -= dataHere;  
  76.     } else {  
  77.       offset = dataHere - prevBytes;  
  78.       break;  
  79.     }  
  80.   }  
  81.   
  82.   
  83.   // dequeue any segments that we no longer need:  
  84.   while (fSegments->headIndex() != i) {  
  85.     fSegments->dequeue(); // we're done with it  
  86.   }  
  87.   
  88.   
  89.   unsigned bytesToUse = tailSeg->aduSize;  
  90.   while (bytesToUse > 0) {  
  91.     Segment& seg = fSegments->s[i];  
  92.     unsigned char* fromPtr  
  93.       = &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset];  
  94.     unsigned dataHere = seg.dataHere() - offset;  
  95.     unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse;  
  96.     memmove(toPtr, fromPtr, bytesUsedHere);  
  97.     bytesToUse -= bytesUsedHere;  
  98.     toPtr += bytesUsedHere;  
  99.     offset = 0;  
  100.     i = SegmentQueue::nextIndex(i);  
  101.   }  
  102.   
  103.   
  104.   
  105.   
  106.   if (fFrameCounter++%fScale == 0) {  //快进快退操作,丢弃不需要的帧  
  107.     // Call our own 'after getting' function.  Because we're not a 'leaf'  
  108.     // source, we can call this directly, without risking infinite recursion.  
  109.     afterGetting(this);  
  110.   } else {  
  111.     // Don't use this frame; get another one:  
  112.     doGetNextFrame();  
  113.   }  
  114.   
  115.   
  116.   return True;  
  117. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值