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

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

    • 分享

      H264--NAL層的處理--3

       mediatv 2013-01-23
      ------------------------------
      H.264的NAL層處理

      ------------------------------


      H264
      NALUNAL unit)為單位來支持編碼數(shù)據(jù)在基于分組交換技術(shù)網(wǎng)絡(luò)中傳輸。

      NALU定義了可用于基于分組和基于比特流系統(tǒng)的基本格式,同時(shí)給出頭信息,從而提供了視頻編碼和外部世界的接口。



      H264編碼過程中的三種不同的數(shù)據(jù)形式:

      SODB
       數(shù)據(jù)比特串-->最原始的編碼數(shù)據(jù),即VCL數(shù)據(jù);

      RBSP
       原始字節(jié)序列載荷-->在SODB的后面填加了結(jié)尾比特(RBSP trailing bits 一個(gè)bit“1”)若干比特“0”,以便字節(jié)對(duì)齊;

      EBSP
       擴(kuò)展字節(jié)序列載荷-->RBSP基礎(chǔ)上填加了仿校驗(yàn)字節(jié)(0X03)它的原因是: 在NALU加到Annexb上時(shí),需要添加每組NALU之前的開始碼StartCodePrefix,如果該NALU對(duì)應(yīng)的slice為一幀的開始則用4位字節(jié)表示,ox00000001,否則用3位字節(jié)表示ox000001(是一幀的一部分)。另外,為了使NALU主體中不包括與開始碼相沖突的,在編碼時(shí),每遇到兩個(gè)字節(jié)連續(xù)為0,就插入一個(gè)字節(jié)的0x03。解碼時(shí)將0x03去掉。也稱為脫殼操作。

      編碼處理過程:

      1
        VCL層輸出的SODB封裝成nal_unit NALU是一個(gè)通用封裝格式,可以適用于有序字節(jié)流方式和IP包交換方式。

      2
        針對(duì)不同的傳送網(wǎng)絡(luò)(電路交換|包交換),將nal_unit封裝成針對(duì)不同網(wǎng)絡(luò)的封裝格式(比如把nalu封裝成rtp包)。



      ---------------------------------------------------

      處理過程一,VCL數(shù)據(jù)封裝成NALU

      ---------------------------------------------------


      VCL層輸出的比特流SODBString Of Data Bits),到nal_unit之間,經(jīng)過了以下三步處理:

      1.SODB
      字節(jié)對(duì)齊處理后封裝成RBSPRaw Byte Sequence Payload)。

      2.
      為防止RBSP的字節(jié)流與有序字節(jié)流傳送方式下的SCPstart_code_prefix_one_3bytes,0x000001)出現(xiàn)字節(jié)競(jìng)爭情形,循環(huán)檢測(cè)RBSP前三個(gè)字節(jié),在出現(xiàn)字節(jié)競(jìng)爭時(shí)在第三字節(jié)前加入emulation_prevention_three_byte0x03),具體方法: 

      nal_unit( NumBytesInNALunit ) {

      forbidden_zero_bit

      nal_ref_idc

      nal_unit_type

      NumBytesInRBSP = 0

      for( i = 1; i < NumBytesInNALunit; i++ ) {

      if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {

      rbsp_byte[ NumBytesInRBSP++ ]

      rbsp_byte[ NumBytesInRBSP++ ]

      i += 2

      emulation_prevention_three_byte /* equal to 0x03 */

      } else

      rbsp_byte[ NumBytesInRBSP++ ]

      }

      }

      3. 
      防字節(jié)競(jìng)爭處理后的RBSP再加一個(gè)字節(jié)的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封裝成
      nal_unit. 

      ------------------------------------------------

      處理過程二,NALU的RTP打包

      ------------------------------------------------

      一、NALU打包成RTP的方式有三種:

      1. 單一 NAL 單元模式
           即一個(gè) RTP 包僅由一個(gè)完整的 NALU 組成. 這種情況下 RTP NAL 頭類型字段和原始的 H.264的
      NALU 頭類型字段是一樣的.

      2. 組合封包模式
          即可能是由多個(gè) NAL 單元組成一個(gè) RTP 包. 分別有4種組合方式: STAP-A, STAP-B, MTAP16, MTAP24.
      那么這里的類型值分別是 24, 25, 26 以及 27.

      3. 分片封包模式
          用于把一個(gè) NALU 單元封裝成多個(gè) RTP 包. 存在兩種類型 FU-A 和 FU-B. 類型值分別是 28 和 29.

       

      還記得前面nal_unit_type的定義吧,0~23是給H264用的,24~31未使用,在rtp打包時(shí),如果一個(gè)NALU放在一個(gè)RTP包里,可 以使用NALU的nal_unit_type,但是當(dāng)需要把多個(gè)NALU打包成一個(gè)RTP包,或者需要把一個(gè)NALU打包成多個(gè)RTP包時(shí),就定義新的 type來標(biāo)識(shí)。

            Type   Packet      Type name                       
            ---------------------------------------------------------
            0      undefined                                    -
            1-23   NAL unit    Single NAL unit packet per H.264  
            24     STAP-A     Single-time aggregation packet    
            25     STAP-B     Single-time aggregation packet    
            26     MTAP16    Multi-time aggregation packet     
            27     MTAP24    Multi-time aggregation packet     
            28     FU-A      Fragmentation unit                
            29     FU-B      Fragmentation unit                 
            30-31  undefined                   
                      

       

      二、三種打包方式的具體格式

      1 .單一 NAL 單元模式

      對(duì)于 NALU 的長度小于 MTU 大小的包, 一般采用單一 NAL 單元模式.
      對(duì)于一個(gè)原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用于標(biāo)示這是一個(gè)

      NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個(gè)字節(jié), 其后都是 NALU 單元內(nèi)容.
      打包時(shí)去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他數(shù)據(jù)封包的 RTP 包即可.

             0                   1                   2                   3
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |F|NRI| type   |                                               |
            +-+-+-+-+-+-+-+-+                                               |
            |                                                               |
            |               Bytes 2..n of a Single NAL unit                 |
            |                                                               |
            |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                               :...OPTIONAL RTP padding        |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


      如有一個(gè) H.264 的 NALU 是這樣的:

      [00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]

      這是一個(gè)序列參數(shù)集 NAL 單元. [00 00 00 01] 是四個(gè)字節(jié)的開始碼, 67 是 NALU 頭, 42 開始的數(shù)據(jù)是 NALU 內(nèi)容.

      封裝成 RTP 包將如下:

      [ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]

      即只要去掉 4 個(gè)字節(jié)的開始碼就可以了.


      2 組合封包模式

      其次, 當(dāng) NALU 的長度特別小時(shí), 可以把幾個(gè) NALU 單元封在一個(gè) RTP 包中.


             0                   1                   2                   3
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                          RTP Header                           |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                         NALU 1 Data                           |
            :                                                               :
            +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |               | NALU 2 Size                   | NALU 2 HDR    |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                         NALU 2 Data                           |
            :                                                               :
            |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                               :...OPTIONAL RTP padding        |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


      3 Fragmentation Units (FUs).

      而當(dāng) NALU 的長度超過 MTU 時(shí), 就必須對(duì) NALU 單元進(jìn)行分片封包. 也稱為 Fragmentation Units (FUs).

             0                   1                   2                   3
             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            | FU indicator |   FU header   |                               |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
            |                                                               |
            |                         FU payload                            |
            |                                                               |
            |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
            |                               :...OPTIONAL RTP padding        |
            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

            Figure 14. RTP payload format for FU-A

         FU indicator有以下格式:
            +---------------+
            |0|1|2|3|4|5|6|7|
            +-+-+-+-+-+-+-+-+
            |F|NRI|  Type   |
            +---------------+
         FU指示字節(jié)的類型域 Type=28表示FU-A。。NRI域的值必須根據(jù)分片NAL單元的NRI域的值設(shè)置。
       
         FU header的格式如下:
            +---------------+
            |0|1|2|3|4|5|6|7|
            +-+-+-+-+-+-+-+-+
            |S|E|R|  Type   |
            +---------------+
         S: 1 bit
         當(dāng)設(shè)置成1,開始位指示分片NAL單元的開始。當(dāng)跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設(shè)為0。
         E: 1 bit
         當(dāng)設(shè)置成1, 結(jié)束位指示分片NAL單元的結(jié)束,即, 荷載的最后字節(jié)也是分片NAL單元的最后一個(gè)字節(jié)。當(dāng)跟隨的FU荷載不是分片NAL單元的最后分片,結(jié)束位設(shè)置為0。
         R: 1 bit
         保留位必須設(shè)置為0,接收者必須忽略該位。
         Type: 5 bits

      三、拆包和解包

      拆包:當(dāng)編碼器在編碼時(shí)需要將原有一個(gè)NAL按照FU-A進(jìn)行分片,原有的NAL的單元頭與分片后的FU-A的單元頭有如下關(guān)系:
      原始的NAL頭的前三位為FU indicator的前三位,原始的NAL頭的后五位為FU header的后五位,F(xiàn)U indicator與FU header的剩余位數(shù)根據(jù)實(shí)際情況決定。
       
      解包:當(dāng)接收端收到FU-A的分片數(shù)據(jù),需要將所有的分片包組合還原成原始的NAl包時(shí),F(xiàn)U-A的單元頭與還原后的NAL的關(guān)系如下:
      還原后的NAL頭的八位是由FU indicator的前三位加FU header的后五位組成,即:
      nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

      四、代碼實(shí)現(xiàn)

      從RTP包里面得到H264視頻數(shù)據(jù)的方法:

       

       
       // 功能:解碼RTP H.264視頻
       // 參數(shù):1.RTP包緩沖地址 2.RTP包數(shù)據(jù)大小 3.H264輸出地址 4.輸出數(shù)據(jù)大小
       // 返回:true:表示一幀結(jié)束  false:FU-A分片未結(jié)束或幀未結(jié)束 
       
      #define  RTP_HEADLEN 12 
       bool  UnpackRTPH264( void   *  bufIn,  int  len,   void **  pBufOut,   int   *  pOutLen)
        {
           * pOutLen  =   0 ;
           if  (len  <  RTP_HEADLEN)
            {
               return   false ;
          } 

       
          unsigned  char *  src  =  (unsigned  char * )bufIn  +  RTP_HEADLEN;
          unsigned  char  head1  =   * src; // 獲取第一個(gè)字節(jié) 
       
          unsigned  char  head2  =   * (src + 1 ); // 獲取第二個(gè)字節(jié) 
       
          unsigned  char  nal  =  head1  &   0x1f ; // 獲取FU indicator的類型域, 
       
          unsigned  char  flag  =  head2  &   0xe0 ; // 獲取FU header的前三位,判斷當(dāng)前是分包的開始、中間或結(jié)束 
       
          unsigned  char  nal_fua  =  (head1  &   0xe0 )  |  (head2  &   0x1f ); // FU_A nal 
       
           bool  bFinishFrame  =   false ;
           if  (nal == 0x1c ) // 判斷NAL的類型為0x1c=28,說明是FU-A分片 
        
            // fu-a 
       
               if  (flag == 0x80 ) // 開始 
        
                {
                   * pBufOut  =  src - 3 ;
                   * (( int * )( * pBufOut))  =   0x01000000  ; // zyf:大模式會(huì)有問題 
       
                   * (( char * )( * pBufOut) + 4 )  =  nal_fua;
                   *  pOutLen  =  len  -  RTP_HEADLEN  +   3 ;
              } 

               else   if (flag == 0x40 ) // 結(jié)束 
        
                {
                   * pBufOut  =  src + 2 ;
                   *  pOutLen  =  len  -  RTP_HEADLEN  -   2 ;
              } 

               else // 中間 
        
                {
                   * pBufOut  =  src + 2 ;
                   *  pOutLen  =  len  -  RTP_HEADLEN  -   2 ;
              } 

          } 

           else // 單包數(shù)據(jù) 
        
            {
               * pBufOut  =  src - 4 ;
               * (( int * )( * pBufOut))  =   0x01000000 ; // zyf:大模式會(huì)有問題 
       
               *  pOutLen  =  len  -  RTP_HEADLEN  +   4 ;
          } 

       
          unsigned  char *  bufTmp  =  (unsigned  char * )bufIn;
           if  (bufTmp[ 1 ]  &   0x80 )
            {
              bFinishFrame  =   true ; // rtp mark 
       
          } 

           else 
             {
              bFinishFrame  =   false ;
          } 

           return  bFinishFrame;
        


      從RTP包里面得到AAC音頻數(shù)據(jù)的方法:


      //功能:解RTP AAC音頻包,聲道和采樣頻率必須知道。
      //參數(shù):1.RTP包緩沖地址 2.RTP包數(shù)據(jù)大小 3.H264輸出地址 4.輸出數(shù)據(jù)大小
      //返回:true:表示一幀結(jié)束  false:幀未結(jié)束 一般AAC音頻包比較小,沒有分片。
      bool UnpackRTPAAC(void * bufIn, int recvLen, void** pBufOut,  int* pOutLen)
      {
          unsigned char*  bufRecv = (unsigned char*)bufIn;
          //char strFileName[20];
          
          unsigned char ADTS[] = {0xFF, 0xF1, 0x00, 0x00, 0x00, 0x00, 0xFC}
          int audioSamprate = 32000;//音頻采樣率
          int audioChannel = 2;//音頻聲道 1或2
          int audioBit = 16;//16位 固定
          switch(audioSamprate)
          {
          case  16000:
              ADTS[2] = 0x60;
              break;
          case  32000:
              ADTS[2] = 0x54;
              break;
          case  44100:
              ADTS[2] = 0x50;
              break;
          case  48000:
              ADTS[2] = 0x4C;
              break;
          case  96000:
              ADTS[2] = 0x40;
              break;
          default:
              break;
          }

          ADTS[3] = (audioChannel==2)?0x80:0x40;

          int len = recvLen - 16 + 7;
          len <<= 5;//8bit * 2 - 11 = 5(headerSize 11bit)
          len |= 0x1F;//5 bit    1            
          ADTS[4] = len>>8;
          ADTS[5] = len & 0xFF;
          *pBufOut = (char*)bufIn+16-7;
          memcpy(*pBufOut, ADTS, sizeof(ADTS));
          *pOutLen = recvLen - 16 + 7;

          unsigned char* bufTmp = (unsigned char*)bufIn;
          bool bFinishFrame = false;
          if (bufTmp[1] & 0x80)
          {
              //DebugTrace::D("Marker");
              bFinishFrame = true;
          }

          else
          {
              bFinishFrame = false;
          }

          return true;
      }

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(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)論公約

        類似文章 更多