乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      live555源碼分析

       gljin_cn 2016-02-15
          現(xiàn)在來分析live555中關(guān)于H264的處理部分,主要包括從文件中讀取數(shù)據(jù)進(jìn)行并進(jìn)行frame(NALU)的分割,然后對(duì)frame進(jìn)行分片,這些工作都是在frame交給RTP sink之前完成的。接著上篇分析文章(RTP的打包與發(fā)送)中提到的MultiFramedRTP::packFrame函數(shù)進(jìn)行分析。
      1. void MultiFramedRTPSink::packFrame() {  
      2.   if (fOutBuf->haveOverflowData()) {  
      3. ...  
      4.   } else {  
      5. ...  
      6.   
      7.   
      8.     //  
      9.     //從source中獲取下一個(gè)frame  
      10.     //  
      11.     fSource->getNextFrame(fOutBuf->curPtr(), fOutBuf->totalBytesAvailable(),  
      12.               afterGettingFrame, this, ourHandleClosure, this);  
      13.   }  
      14. }  


          getNextFrame是定義在FramedSource中的非虛函數(shù),從source中獲取下一個(gè)frame,然后調(diào)用回調(diào)函數(shù)afterGettingFrame。afterGettingFrame被定義為靜態(tài)函數(shù),因?yàn)樵贑++中類成員函數(shù)是不能作為回調(diào)用函數(shù)的。不過這里為什么要用回調(diào)函數(shù)回?
          注意,對(duì)于H264來說,上面的fSource并不是MPEGVideoStreamFramer類,因?yàn)樵?H264VideoRTPSink::continuePlaying()函數(shù)中改變了fSource的值。    
      1. Boolean H264VideoRTPSink::continuePlaying() {  
      2.   // First, check whether we have a 'fragmenter' class set up yet.  
      3.   // If not, create it now:  
      4.   if (fOurFragmenter == NULL) {  
      5.     //創(chuàng)建一個(gè)輔助類H264FUAFragmenter,用于H264按照RFC3984進(jìn)行RTP打包  
      6.   
      7.     fOurFragmenter = new H264FUAFragmenter(envir(), fSource, OutPacketBuffer::maxSize,  
      8.                        ourMaxPacketSize() - 12/*RTP hdr size*/);  
      9.     fSource = fOurFragmenter;  
      10.   }  
      11.   
      12.   
      13.   // Then call the parent class's implementation:  
      14.   return MultiFramedRTPSink::continuePlaying();  
      15. }  


          fSource被指向了H264FUAFragmenter類,這個(gè)類主要實(shí)現(xiàn)了H264按照RFC3984進(jìn)行RTP分包,不過這里的實(shí)現(xiàn)每個(gè)RTP中最多只包含一個(gè)NALU,沒有實(shí)現(xiàn)組合封包的情形。這個(gè)類的繼承關(guān)系如下:H264FUAFragmenter->FramedFilter->FramedSource。很明顯,這是一個(gè)filter,包裝了MPEGVideoStreamFramer類的對(duì)像。
          先來看來看getNextFrame的實(shí)現(xiàn)

      1. void FramedSource::getNextFrame(unsigned char* to, unsigned maxSize,  
      2.                 afterGettingFunc* afterGettingFunc,  
      3.                 void* afterGettingClientData,  
      4.                 onCloseFunc* onCloseFunc,  
      5.                 void* onCloseClientData) {  
      6.   // Make sure we're not already being read:  
      7.   if (fIsCurrentlyAwaitingData) {  
      8.     envir() << "FramedSource[" << this << "]::getNextFrame(): attempting to read more than once at the same time!\n";  
      9.     envir().internalError();  
      10.   }  
      11.   
      12.   
      13.   fTo = to;             //buffer地址  
      14.   fMaxSize = maxSize;   //buffer最大長(zhǎng)度  
      15.   fNumTruncatedBytes = 0; // by default; could be changed by doGetNextFrame()  
      16.   fDurationInMicroseconds = 0; // by default; could be changed by doGetNextFrame()  
      17.   fAfterGettingFunc = afterGettingFunc;             //獲取完一個(gè)frame后將執(zhí)行這個(gè)函數(shù)  
      18.   fAfterGettingClientData = afterGettingClientData; //這個(gè)參數(shù)就是MultiFramedRTPSink類型指針  
      19.   fOnCloseFunc = onCloseFunc;  
      20.   fOnCloseClientData = onCloseClientData;  
      21.   fIsCurrentlyAwaitingData = True;  
      22.   
      23.   
      24.   doGetNextFrame();  
      25. }  


          上面的函數(shù)主要是進(jìn)行一些成員變量的初始化,獲取到的frame需要保存到fTo地址中,然后調(diào)用fAfterGettingFunc函數(shù),若文件讀取完畢,還需要調(diào)用fOnCloseFunc函數(shù)。重要的工作還是在doGetNextFrame函數(shù)中完成,不過它是定義在FramedSource類中的純虛函數(shù),需要在子類中重新實(shí)現(xiàn)。
          現(xiàn)在來看H264FUAFragmenter中對(duì)doGetNextFrame的實(shí)現(xiàn)

      1. void H264FUAFragmenter::doGetNextFrame() {  
      2.   if (fNumValidDataBytes == 1) {  
      3.       //讀取一個(gè)新的frame  
      4.     // We have no NAL unit data currently in the buffer.  Read a new one:  
      5.     fInputSource->getNextFrame(&fInputBuffer[1], fInputBufferSize - 1,  
      6.                    afterGettingFrame, this,  
      7.                    FramedSource::handleClosure, this);  
      8.   } else {  
      9.       //  
      10.       //現(xiàn)在buffer中已經(jīng)存在NALU數(shù)據(jù)了,需要考慮三種情況  
      11.       //1.一個(gè)新的NALU,且足夠小能投遞給RTP sink。  
      12.       //2.一個(gè)新的NALU,但是比RTP sink要求的包大了,投遞第一個(gè)分片作為一個(gè)FU-A packet, 并帶上一個(gè)額外的頭字節(jié)。  
      13.       //3.部分NALU數(shù)據(jù),投遞下一個(gè)分片作為一個(gè)FU-A packet,并帶上2個(gè)額外的頭字節(jié)。  
      14.     // We have NAL unit data in the buffer.  There are three cases to consider:  
      15.     // 1. There is a new NAL unit in the buffer, and it's small enough to deliver  
      16.     //    to the RTP sink (as is).  
      17.     // 2. There is a new NAL unit in the buffer, but it's too large to deliver to  
      18.     //    the RTP sink in its entirety.  Deliver the first fragment of this data,  
      19.     //    as a FU-A packet, with one extra preceding header byte.  
      20.     // 3. There is a NAL unit in the buffer, and we've already delivered some  
      21.     //    fragment(s) of this.  Deliver the next fragment of this data,  
      22.     //    as a FU-A packet, with two extra preceding header bytes.  
      23.   
      24.   
      25.     if (fMaxSize < fMaxOutputPacketSize) { // shouldn't happen  
      26.       envir() << "H264FUAFragmenter::doGetNextFrame(): fMaxSize ("  
      27.           << fMaxSize << ") is smaller than expected\n";  
      28.     } else {  
      29.       fMaxSize = fMaxOutputPacketSize;  
      30.     }  
      31.   
      32.   
      33.     fLastFragmentCompletedNALUnit = True; // by default  
      34.     if (fCurDataOffset == 1) { // case 1 or 2  
      35.       if (fNumValidDataBytes - 1 <= fMaxSize) { // case 1  
      36.           //  
      37.           //情況1, 處理整個(gè)NALU  
      38.           //  
      39.     memmove(fTo, &fInputBuffer[1], fNumValidDataBytes - 1);  
      40.     fFrameSize = fNumValidDataBytes - 1;  
      41.     fCurDataOffset = fNumValidDataBytes;  
      42.       } else { // case 2  
      43.           //  
      44.           //情況2,處理NALU的第1個(gè)分片。注意,我們添加FU指示符和FU頭字節(jié)(with S bit)到包的最前面(  
      45.           //重用已經(jīng)存在的NAL 頭字節(jié)作為FU的頭字節(jié))  
      46.           //  
      47.     // We need to send the NAL unit data as FU-A packets.  Deliver the first  
      48.     // packet now.  Note that we add FU indicator and FU header bytes to the front  
      49.     // of the packet (reusing the existing NAL header byte for the FU header).  
      50.     fInputBuffer[0] = (fInputBuffer[1] & 0xE0) | 28; // FU indicator  
      51.     fInputBuffer[1] = 0x80 | (fInputBuffer[1] & 0x1F); // FU header (with S bit)   重用NALU頭字節(jié)  
      52.     memmove(fTo, fInputBuffer, fMaxSize);  
      53.     fFrameSize = fMaxSize;  
      54.     fCurDataOffset += fMaxSize - 1;  
      55.     fLastFragmentCompletedNALUnit = False;  
      56.       }  
      57.     } else { // case 3  
      58.         //  
      59.         //情況3,處理非第1個(gè)分片。需要添加FU指示符和FU頭(我們重用了第一個(gè)分片中的字節(jié),但是需要清除S位,  
      60.         //并在最后一個(gè)分片中添加E位)  
      61.         //  
      62.         //  
      63.       // We are sending this NAL unit data as FU-A packets.  We've already sent the  
      64.       // first packet (fragment).  Now, send the next fragment.  Note that we add  
      65.       // FU indicator and FU header bytes to the front.  (We reuse these bytes that  
      66.       // we already sent for the first fragment, but clear the S bit, and add the E  
      67.       // bit if this is the last fragment.)  
      68.       fInputBuffer[fCurDataOffset-2] = fInputBuffer[0]; // FU indicator  
      69.       fInputBuffer[fCurDataOffset-1] = fInputBuffer[1]&~0x80; // FU header (no S bit)  
      70.       unsigned numBytesToSend = 2 + fNumValidDataBytes - fCurDataOffset;  
      71.       if (numBytesToSend > fMaxSize) {  
      72.     // We can't send all of the remaining data this time:  
      73.     numBytesToSend = fMaxSize;  
      74.     fLastFragmentCompletedNALUnit = False;  
      75.       } else {  
      76.     //  
      77.     //最后一個(gè)分片,需要在FU頭中設(shè)置E標(biāo)志位  
      78.     // This is the last fragment:  
      79.     fInputBuffer[fCurDataOffset-1] |= 0x40; // set the E bit in the FU header  
      80.     fNumTruncatedBytes = fSaveNumTruncatedBytes;  
      81.       }  
      82.       memmove(fTo, &fInputBuffer[fCurDataOffset-2], numBytesToSend);  
      83.       fFrameSize = numBytesToSend;  
      84.       fCurDataOffset += numBytesToSend - 2;  
      85.     }  
      86.   
      87.   
      88.     if (fCurDataOffset >= fNumValidDataBytes) {  
      89.       // We're done with this data.  Reset the pointers for receiving new data:  
      90.       fNumValidDataBytes = fCurDataOffset = 1;  
      91.     }  
      92.   
      93.   
      94.     // Complete delivery to the client:  
      95.     FramedSource::afterGetting(this);  
      96.   }  
      97. }  


          H264FUAFragmenter::doGetNextFrame函數(shù)第一次執(zhí)行時(shí),執(zhí)行條件1,需要調(diào)用 MPEGVideoStreamFramer::doGetNextFrame讀取一個(gè)新的frame,獲取frame的具體過程稍后再分析?,F(xiàn)在先看獲取frame之后的工作,afterGettingFrame函數(shù)
      1. void H264FUAFragmenter::afterGettingFrame(void* clientData, unsigned frameSize,  
      2.                       unsigned numTruncatedBytes,  
      3.                       struct timeval presentationTime,  
      4.                       unsigned durationInMicroseconds) {  
      5.   H264FUAFragmenter* fragmenter = (H264FUAFragmenter*)clientData;  
      6.   fragmenter->afterGettingFrame1(frameSize, numTruncatedBytes, presentationTime,  
      7.                  durationInMicroseconds);  
      8. }  


      沒什么好說的,再看afterGettingFrame1函數(shù)


      1. void H264FUAFragmenter::afterGettingFrame1(unsigned frameSize,  
      2.                        unsigned numTruncatedBytes,  
      3.                        struct timeval presentationTime,  
      4.                        unsigned durationInMicroseconds) {  
      5.   fNumValidDataBytes += frameSize;      //保存讀到的frame長(zhǎng)度  
      6.   fSaveNumTruncatedBytes = numTruncatedBytes;  
      7.   fPresentationTime = presentationTime;  
      8.   fDurationInMicroseconds = durationInMicroseconds;  
      9.   
      10.   
      11.   // Deliver data to the client:  
      12.   doGetNextFrame();  
      13. }  


          上面的代碼首先記錄幾個(gè)數(shù)據(jù)到成員變量中,fNumValidDataBytes很重要,表示讀取到的frame長(zhǎng)度+1。然后又一次調(diào)用了H264FUAFragmenter::doGetNextFrame(),這里將進(jìn)入H264FUAFragmenter::doGetNextFrame函數(shù)中第二個(gè)條件分支,這種循環(huán)調(diào)用很容易把人弄迷糊了。

          H264FUAFragmenter::doGetNextFrame函數(shù)中第二個(gè)條件分支中,處理H264的RTP分片問題,這里是按照RFC3984進(jìn)行RTP封裝的。你應(yīng)該注意到,在上篇文章"RTP的打包與發(fā)送"中,也出現(xiàn)了分片的代碼(MultiFramedRTPSink::packFrame函數(shù)中),那里直接將frame按MTU的長(zhǎng)度來拆分。那為什么H264還要自定義一套R(shí)TP打包的標(biāo)準(zhǔn)呢?暫時(shí)我也不清楚。


          在H264FUAFragmenter::doGetNextFrame()最后調(diào)用了 FramedSource::afterGetting


      1. void FramedSource::afterGetting(FramedSource* source) {  
      2.   source->fIsCurrentlyAwaitingData = False;     //表示已經(jīng)獲取到數(shù)據(jù)了,處于非等待狀態(tài)  
      3.       // indicates that we can be read again  
      4.       // Note that this needs to be done here, in case the "fAfterFunc"  
      5.       // called below tries to read another frame (which it usually will)  
      6.   
      7.   
      8.   //通過回調(diào)用進(jìn)行后續(xù)處理  
      9.   if (source->fAfterGettingFunc != NULL) {  
      10.     (*(source->fAfterGettingFunc))(source->fAfterGettingClientData,  
      11.                    source->fFrameSize, source->fNumTruncatedBytes,  
      12.                    source->fPresentationTime,  
      13.                    source->fDurationInMicroseconds);  
      14.   }  
      15. }  



          上面的代碼主要是調(diào)用了FramedSource::getNextFrame函數(shù)中傳遞下來的回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)就是MultiFramedRTPSink::afterGettingFrame,處理過程在上一篇文章"RTP的打包與發(fā)送"中已經(jīng)分析過了。
        
          現(xiàn)在來看MPEGVideoStreamFramer::doGetNextFrame獲取Frame的過程。繼承關(guān)系:H264VideoStreamFramer->MPEGVideoStreamFramer->FramedFilter->FramedSource。在繼承路徑中存在FrameFilter,這說明H264VideoStreamFramer包裝了其它source(包裝的是讀取文件的字節(jié)流source)。doGetNextFrame函數(shù)首先在MPEGVideoStreamFramer中實(shí)現(xiàn)。


      1. void MPEGVideoStreamFramer::doGetNextFrame() {  
      2.   fParser->registerReadInterest(fTo, fMaxSize); //將目的buffer信息注冊(cè)到語(yǔ)法分析類中  
      3.   continueReadProcessing();     //繼續(xù)進(jìn)行讀數(shù)據(jù)  
      4. }  



          這里的MPEGVideoStreamFramer::fParser,是一個(gè)MPEGVideoStreamParser類型指針,作為語(yǔ)法分析器。再來看continueReadProcessing函數(shù)


      1. void MPEGVideoStreamFramer::continueReadProcessing() {  
      2.   unsigned acquiredFrameSize = fParser->parse();    //文件的語(yǔ)法分析(即demux)  
      3.   if (acquiredFrameSize > 0) {  
      4.     // We were able to acquire a frame from the input.  
      5.     // It has already been copied to the reader's space.  
      6.     fFrameSize = acquiredFrameSize;  
      7.     fNumTruncatedBytes = fParser->numTruncatedBytes();  
      8.   
      9.   
      10.     // "fPresentationTime" should have already been computed.  
      11.   
      12.   
      13.     // Compute "fDurationInMicroseconds" now:  
      14.     fDurationInMicroseconds  
      15.       = (fFrameRate == 0.0 || ((int)fPictureCount) < 0) ? 0  
      16.       : (unsigned)((fPictureCount*1000000)/fFrameRate);  
      17. #ifdef DEBUG  
      18.     fprintf(stderr, "%d bytes @%u.%06d, fDurationInMicroseconds: %d ((%d*1000000)/%f)\n", acquiredFrameSize, fPresentationTime.tv_sec, fPresentationTime.tv_usec, fDurationInMicroseconds, fPictureCount, fFrameRate);  
      19. #endif  
      20.     fPictureCount = 0;  
      21.       
      22.     //  
      23.     //調(diào)用自身的afterGetting函數(shù),因?yàn)檫@不一個(gè)"leaf" source, 所以可能直接調(diào)用,  
      24.     //而不用擔(dān)心出現(xiàn)無限遞歸  
      25.     //  
      26.     // Call our own 'after getting' function.  Because we're not a 'leaf'  
      27.     // source, we can call this directly, without risking infinite recursion.  
      28.     afterGetting(this);  
      29.   } else {  
      30.     // We were unable to parse a complete frame from the input, because:  
      31.     // - we had to read more data from the source stream, or  
      32.     // - the source stream has ended.  
      33.   }  
      34. }  


          函數(shù)中首先調(diào)用了MPEGVideoStreamParser::parse函數(shù),將一個(gè)完整的Frame分析出來,并copy到了fTo(fTo就是OutPacketBuffer中的緩沖區(qū))中,這其中肯定也實(shí)現(xiàn)了從文件中讀取數(shù)據(jù)的過程。這里的fNumTruncatedBytes變量需要注意,fNumTruncatedBytes>0的話,表明Frame的實(shí)際長(zhǎng)度大于fTo的最大長(zhǎng)度,這將導(dǎo)致數(shù)據(jù)丟失,這時(shí)就要考慮增加緩沖區(qū)的長(zhǎng)度了。成功獲取一個(gè)Frame后,將調(diào)用afterGetting函數(shù)處理后續(xù)工作。
          先來看parse函數(shù),parse是定義在MPEGVideoStreamParser中的純虛函數(shù),在子類H264VideoStreamParser中實(shí)現(xiàn)。parse主要是從文件的字節(jié)流中,分離出一個(gè)個(gè)的Frame,對(duì)于H264而言其實(shí)就是對(duì)一個(gè)個(gè)的NALU。*.264文件的格式非常簡(jiǎn)單,每個(gè)NALU以 0x00000001 作為起始符號(hào)(中間的NALU也可以以0x000001作為起始符),順序存放。


      1. unsigned H264VideoStreamParser::parse() {  
      2.   try {  
      3.     //  
      4.     //首先找到起始符號(hào), 并跳過。文件流的最開始必需以0x00000001開始,但后續(xù)的NALU充許以0x000001(3 bytes)作為分隔  
      5.     //  
      6.     // The stream must start with a 0x00000001:  
      7.     if (!fHaveSeenFirstStartCode) {  
      8.       // Skip over any input bytes that precede the first 0x00000001:  
      9.       u_int32_t first4Bytes;  
      10.       while ((first4Bytes = test4Bytes()) != 0x00000001) {  
      11.     get1Byte(); setParseState(); // ensures that we progress over bad data  
      12.       }  
      13.       skipBytes(4); // skip this initial code  
      14.         
      15.       setParseState();  
      16.       fHaveSeenFirstStartCode = True; // from now on  
      17.     }  
      18.     //  
      19.     //將起始標(biāo)志也保存到目的緩沖區(qū)中  
      20.     //  
      21.     if (fOutputStartCodeSize > 0) {  
      22.       // Include a start code in the output:  
      23.       save4Bytes(0x00000001);     
      24.     }  
      25.       
      26.     //  
      27.     //保存所有數(shù)據(jù),直至遇到起始標(biāo)志,或者文件結(jié)束符。需要注意NALU中的第一個(gè)字節(jié),因?yàn)樗甘玖薔ALU的類型  
      28.     //  
      29.     // Then save everything up until the next 0x00000001 (4 bytes) or 0x000001 (3 bytes), or we hit EOF.  
      30.     // Also make note of the first byte, because it contains the "nal_unit_type":   
      31.     u_int8_t firstByte;  
      32.     if (haveSeenEOF()) {  
      33.        //  
      34.        //已經(jīng)設(shè)置了文件結(jié)束標(biāo)志,將剩下的數(shù)據(jù)保存也來即可  
      35.        //  
      36.       // We hit EOF the last time that we tried to parse this data,  
      37.       // so we know that the remaining unparsed data forms a complete NAL unit:  
      38.       unsigned remainingDataSize = totNumValidBytes() - curOffset();  
      39.       if (remainingDataSize == 0) (void)get1Byte(); // forces another read, which will cause EOF to get handled for real this time  
      40. #ifdef DEBUG  
      41.       fprintf(stderr, "This NAL unit (%d bytes) ends with EOF\n", remainingDataSize);  
      42. #endif  
      43.       if (remainingDataSize == 0) return 0;  
      44.       firstByte = get1Byte();   //將第一個(gè)字節(jié)保存下來,其指示了NALU的類型  
      45.       saveByte(firstByte);  
      46.         
      47.       while (--remainingDataSize > 0) {  
      48.     saveByte(get1Byte());  
      49.       }  
      50.     } else {  
      51.       u_int32_t next4Bytes = test4Bytes();  
      52.       firstByte = next4Bytes>>24;   //將第一個(gè)字節(jié)保存下來  
      53.       //  
      54.       //將下一個(gè)起始符號(hào)之前的數(shù)據(jù)都保存下來  
      55.       //  
      56.       while (next4Bytes != 0x00000001 && (next4Bytes&0xFFFFFF00) != 0x00000100) {  
      57.     // We save at least some of "next4Bytes".  
      58.     if ((unsigned)(next4Bytes&0xFF) > 1) {  //一次可以保存4個(gè)字節(jié),并不需要一個(gè)一個(gè)字節(jié)對(duì)比,除非到了結(jié)尾  
      59.       // Common case: 0x00000001 or 0x000001 definitely doesn't begin anywhere in "next4Bytes", so we save all of it:  
      60.       save4Bytes(next4Bytes);  
      61.       skipBytes(4);  
      62.     } else {  
      63.       // Save the first byte, and continue testing the rest:  
      64.       saveByte(next4Bytes>>24);  
      65.       skipBytes(1);  
      66.     }  
      67.     next4Bytes = test4Bytes();  
      68.       }  
      69.       // Assert: next4Bytes starts with 0x00000001 or 0x000001, and we've saved all previous bytes (forming a complete NAL unit).  
      70.       // Skip over these remaining bytes, up until the start of the next NAL unit:  
      71.       if (next4Bytes == 0x00000001) {  
      72.     skipBytes(4);  
      73.       } else {  
      74.     skipBytes(3);  
      75.       }  
      76.     }  
      77.    
      78.     u_int8_t nal_ref_idc = (firstByte&0x60)>>5;  
      79.     u_int8_t nal_unit_type = firstByte&0x1F;  
      80. #ifdef DEBUG  
      81.     fprintf(stderr, "Parsed %d-byte NAL-unit (nal_ref_idc: %d, nal_unit_type: %d (\"%s\"))\n",  
      82.         curFrameSize()-fOutputStartCodeSize, nal_ref_idc, nal_unit_type, nal_unit_type_description[nal_unit_type]);  
      83. #endif  
      84.   
      85.   
      86.     //  
      87.     //下面根據(jù)NALU的類型來作具體的分析  
      88.     //  
      89.     switch (nal_unit_type) {  
      90.       case 6: { // Supplemental enhancement information (SEI)  
      91.     analyze_sei_data();  
      92.     // Later, perhaps adjust "fPresentationTime" if we saw a "pic_timing" SEI payload??? #####  
      93.     break;  
      94.       }  
      95.       case 7: { // Sequence parameter set (序列參數(shù)集)  
      96.       //  
      97.       //保存一份SPS的副本到H264VideoStreamFramer中,后面的pps也需要保存,sps中可能還包含了幀率信息  
      98.       //  
      99.     // First, save a copy of this NAL unit, in case the downstream object wants to see it:  
      100.     usingSource()->saveCopyOfSPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);  
      101.   
      102.   
      103.     // Parse this NAL unit to check whether frame rate information is present:  
      104.     unsigned num_units_in_tick, time_scale, fixed_frame_rate_flag;  
      105.     analyze_seq_parameter_set_data(num_units_in_tick, time_scale, fixed_frame_rate_flag);  
      106.     if (time_scale > 0 && num_units_in_tick > 0) {  
      107.       usingSource()->fFrameRate = time_scale/(2.0*num_units_in_tick);   //sps中包含了幀率信息  
      108. #ifdef DEBUG  
      109.       fprintf(stderr, "Set frame rate to %f fps\n", usingSource()->fFrameRate);  
      110.       if (fixed_frame_rate_flag == 0) {  
      111.         fprintf(stderr, "\tWARNING: \"fixed_frame_rate_flag\" was not set\n");  
      112.       }  
      113. #endif  
      114.     } else {    //sps中不包含幀率信息,則使用source中設(shè)置的默認(rèn)幀率  
      115. #ifdef DEBUG  
      116.       fprintf(stderr, "\tThis \"Sequence Parameter Set\" NAL unit contained no frame rate information, so we use a default frame rate of %f fps\n", usingSource()->fFrameRate);  
      117. #endif  
      118.     }  
      119.     break;  
      120.       }  
      121.       case 8: { // Picture parameter set (圖像參數(shù)集PPS)  
      122.     // Save a copy of this NAL unit, in case the downstream object wants to see it:  
      123.     usingSource()->saveCopyOfPPS(fStartOfFrame + fOutputStartCodeSize, fTo - fStartOfFrame - fOutputStartCodeSize);  
      124.       }  
      125.     }  
      126.       
      127.     usingSource()->setPresentationTime();   //設(shè)置當(dāng)前的時(shí)間  
      128. #ifdef DEBUG  
      129.     unsigned long secs = (unsigned long)usingSource()->fPresentationTime.tv_sec;  
      130.     unsigned uSecs = (unsigned)usingSource()->fPresentationTime.tv_usec;  
      131.     fprintf(stderr, "\tPresentation time: %lu.%06u\n", secs, uSecs);  
      132. #endif  
      133.       
      134.     //  
      135.     //如果這個(gè)NALU是一個(gè)VCL NALU(即包含的是視頻數(shù)據(jù)),我們需要掃描下一個(gè)NALU的起始符,  
      136.     //以判斷這個(gè)NALU是否是當(dāng)前的"access unit"(這個(gè)"access unit"應(yīng)該可以理解為一幀圖像幀吧)。  
      137.     //我們需要根據(jù)這個(gè)信息去指明何時(shí)該增加"fPresentationTime"(RTP 打包時(shí)也需要根據(jù)這個(gè)信息,決定是否設(shè)置"M"位)。  
      138.     //  
      139.     // If this NAL unit is a VCL NAL unit, we also scan the start of the next NAL unit, to determine whether this NAL unit  
      140.     // ends the current 'access unit'.  We need this information to figure out when to increment "fPresentationTime".  
      141.     // (RTP streamers also need to know this in order to figure out whether or not to set the "M" bit.)  
      142.     Boolean thisNALUnitEndsAccessUnit = False; // until we learn otherwise   
      143.     if (haveSeenEOF()) {  
      144.       // There is no next NAL unit, so we assume that this one ends the current 'access unit':  
      145.       thisNALUnitEndsAccessUnit = True;  
      146.     } else {  
      147.       Boolean const isVCL = nal_unit_type <= 5 && nal_unit_type > 0; // Would need to include type 20 for SVC and MVC #####  
      148.       if (isVCL) {  
      149.     u_int32_t first4BytesOfNextNALUnit = test4Bytes();  
      150.     u_int8_t firstByteOfNextNALUnit = first4BytesOfNextNALUnit>>24;  
      151.     u_int8_t next_nal_ref_idc = (firstByteOfNextNALUnit&0x60)>>5;  
      152.     u_int8_t next_nal_unit_type = firstByteOfNextNALUnit&0x1F;  
      153.     if (next_nal_unit_type >= 6) {  
      154.         //下一個(gè)NALU不是VCL的,當(dāng)前的"access unit"結(jié)束了  
      155.       // The next NAL unit is not a VCL; therefore, we assume that this NAL unit ends the current 'access unit':  
      156. #ifdef DEBUG  
      157.       fprintf(stderr, "\t(The next NAL unit is not a VCL)\n");  
      158. #endif  
      159.       thisNALUnitEndsAccessUnit = True;  
      160.     } else {  
      161.         //下一個(gè)NALU也是VCL的,還需要檢查一下它們是不是屬于同一個(gè)"access unit"  
      162.       // The next NAL unit is also a VLC.  We need to examine it a little to figure out if it's a different 'access unit'.  
      163.       // (We use many of the criteria described in section 7.4.1.2.4 of the H.264 specification.)  
      164.       Boolean IdrPicFlag = nal_unit_type == 5;  
      165.       Boolean next_IdrPicFlag = next_nal_unit_type == 5;  
      166.       if (next_IdrPicFlag != IdrPicFlag) {  
      167.         // IdrPicFlag differs in value  
      168. #ifdef DEBUG  
      169.         fprintf(stderr, "\t(IdrPicFlag differs in value)\n");  
      170. #endif  
      171.         thisNALUnitEndsAccessUnit = True;  
      172.       } else if (next_nal_ref_idc != nal_ref_idc && next_nal_ref_idc*nal_ref_idc == 0) {  
      173.         // nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0  
      174. #ifdef DEBUG  
      175.         fprintf(stderr, "\t(nal_ref_idc differs in value with one of the nal_ref_idc values being equal to 0)\n");  
      176. #endif  
      177.         thisNALUnitEndsAccessUnit = True;  
      178.       } else if ((nal_unit_type == 1 || nal_unit_type == 2 || nal_unit_type == 5)  
      179.              && (next_nal_unit_type == 1 || next_nal_unit_type == 2 || next_nal_unit_type == 5)) {  
      180.         // Both this and the next NAL units begin with a "slice_header".  
      181.         // Parse this (for each), to get parameters that we can compare:  
      182.           
      183.         // Current NAL unit's "slice_header":  
      184.         unsigned frame_num, pic_parameter_set_id, idr_pic_id;  
      185.         Boolean field_pic_flag, bottom_field_flag;  
      186.         analyze_slice_header(fStartOfFrame + fOutputStartCodeSize, fTo, nal_unit_type,  
      187.                  frame_num, pic_parameter_set_id, idr_pic_id, field_pic_flag, bottom_field_flag);  
      188.           
      189.         // Next NAL unit's "slice_header":  
      190. #ifdef DEBUG  
      191.         fprintf(stderr, "    Next NAL unit's slice_header:\n");  
      192. #endif  
      193.         u_int8_t next_slice_header[NUM_NEXT_SLICE_HEADER_BYTES_TO_ANALYZE];  
      194.         testBytes(next_slice_header, sizeof next_slice_header);  
      195.         unsigned next_frame_num, next_pic_parameter_set_id, next_idr_pic_id;  
      196.         Boolean next_field_pic_flag, next_bottom_field_flag;  
      197.         analyze_slice_header(next_slice_header, &next_slice_header[sizeof next_slice_header], next_nal_unit_type,  
      198.                  next_frame_num, next_pic_parameter_set_id, next_idr_pic_id, next_field_pic_flag, next_bottom_field_flag);  
      199.           
      200.         if (next_frame_num != frame_num) {  
      201.           // frame_num differs in value  
      202. #ifdef DEBUG  
      203.           fprintf(stderr, "\t(frame_num differs in value)\n");  
      204. #endif  
      205.           thisNALUnitEndsAccessUnit = True;  
      206.         } else if (next_pic_parameter_set_id != pic_parameter_set_id) {  
      207.           // pic_parameter_set_id differs in value  
      208. #ifdef DEBUG  
      209.           fprintf(stderr, "\t(pic_parameter_set_id differs in value)\n");  
      210. #endif  
      211.           thisNALUnitEndsAccessUnit = True;  
      212.         } else if (next_field_pic_flag != field_pic_flag) {  
      213.           // field_pic_flag differs in value  
      214. #ifdef DEBUG  
      215.           fprintf(stderr, "\t(field_pic_flag differs in value)\n");  
      216. #endif  
      217.           thisNALUnitEndsAccessUnit = True;  
      218.         } else if (next_bottom_field_flag != bottom_field_flag) {  
      219.           // bottom_field_flag differs in value  
      220. #ifdef DEBUG  
      221.           fprintf(stderr, "\t(bottom_field_flag differs in value)\n");  
      222. #endif  
      223.           thisNALUnitEndsAccessUnit = True;  
      224.         } else if (next_IdrPicFlag == 1 && next_idr_pic_id != idr_pic_id) {  
      225.           // IdrPicFlag is equal to 1 for both and idr_pic_id differs in value  
      226.           // Note: We already know that IdrPicFlag is the same for both.  
      227. #ifdef DEBUG  
      228.           fprintf(stderr, "\t(IdrPicFlag is equal to 1 for both and idr_pic_id differs in value)\n");  
      229. #endif  
      230.           thisNALUnitEndsAccessUnit = True;  
      231.         }  
      232.       }  
      233.     }  
      234.       }  
      235.     }  
      236.       
      237.     if (thisNALUnitEndsAccessUnit) {  
      238. #ifdef DEBUG  
      239.       fprintf(stderr, "*****This NAL unit ends the current access unit*****\n");  
      240. #endif  
      241.       usingSource()->fPictureEndMarker = True;  //這里就是設(shè)置RTP打包時(shí)用到的M標(biāo)志了  
      242.       ++usingSource()->fPictureCount;  
      243.   
      244.   
      245.       //  
      246.       //下一個(gè)NALU不再屬于當(dāng)前"access unit""時(shí),才改變時(shí)間  
      247.       //  
      248.       // Note that the presentation time for the next NAL unit will be different:  
      249.       struct timeval& nextPT = usingSource()->fNextPresentationTime; // alias 這里是引用   
      250.       nextPT = usingSource()->fPresentationTime;  
      251.       double nextFraction = nextPT.tv_usec/1000000.0 + 1/usingSource()->fFrameRate;   
      252.       unsigned nextSecsIncrement = (long)nextFraction;  
      253.       nextPT.tv_sec += (long)nextSecsIncrement;  
      254.       nextPT.tv_usec = (long)((nextFraction - nextSecsIncrement)*1000000);  
      255.     }  
      256.     setParseState();  
      257.   
      258.   
      259.     return curFrameSize();  
      260.   } catch (int /*e*/) {  
      261. #ifdef DEBUG  
      262.     fprintf(stderr, "H264VideoStreamParser::parse() EXCEPTION (This is normal behavior - *not* an error)\n");  
      263. #endif  
      264.     return 0;  // the parsing got interrupted  
      265.   }  
      266. }  


          H264VideoStreamParser::parse()函數(shù)除了取出Frame,還對(duì)NALU中的部分參數(shù)做了解釋工作。對(duì)于PPS或者SPS類型的NALU,要保存到H264VideoStreamFramer中。"access unit",在這里可以理解為一副圖像,一個(gè)"access unit"可以包含多個(gè)NALU,很顯示這些NALU的時(shí)間戳應(yīng)該是相同的。實(shí)際上,很多時(shí)候一個(gè)"access unit"單元只包含一個(gè)NALU,這里簡(jiǎn)單多了。分析過程是根據(jù)section 7.4.1.2.4 of the H.264 specification進(jìn)行的。


        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多