Rtp載荷H264解包過程分析,ffmpeg解碼qt展示

一、H264流格式  

1.H264算法在概念上分爲兩層:    

        VCL層:視頻編碼層,負責高效的內容表示;    

        NAL層:網絡提取層,負責對視頻數據進行打包和傳送。    

        今天主要記錄一下NAL層的知識,以備後期查看。

2.網絡抽象層單元 (NALU)

       NALU 頭由一個字節組成, 它的語法如下: 
      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type  |
      +---------------+ 

     F: 1 個比特.  forbidden_zero_bit. 在 H.264 規範中規定了這一位必須爲 0. 
     NRI: 2 個比特. nal_ref_idc. 取 00 ~ 11, 似乎指示這個 NALU 的重要性, 如 00 的 NALU 解碼器可以丟棄它而不影響圖像,不過一般情況下不太關心這個屬性. 
     Type: 5 個比特.nal_unit_type. 這個 NALU 單元的類型. 
     Type       Packet                 Type name                        
      -------------------------------------------------------------------
      0           undefined                                    
      1-23      NAL unit     Single NAL unit packet per H.264  

      1     不分區,非IDR圖像的片
      2     片分區A
      3     片分區B
      4     片分區C
      5     IDR圖像中的片
      6     補充增強信息單元(SEI)
      7     SPS
      8     PPS
      9     序列結束
     10    序列結束
     11    碼流借宿
     12    填充
     13-23 保留 
      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------------------------------------

     H264 over RTP基本上分三種類型:
     (1)Single NAL unit packet 也就是實際的NAL類型,可以理解爲一個包就是一幀H264數據,這個在實際中是比較多的。
     (2)Aggregation packet 一包數據中含有多個H264幀。
     STAP-A 包內的幀含有相同的NALU-Time,沒有DON
     STAP-B 包內的幀含有相同的NALU-Time,有DON
     MTAP16 包內的幀含有不同的NALU-Time,timestamp offset = 16
     MTAP24 包內的幀含有不同的NALU-Time,timestamp offset = 24
     封裝在Aggregation packet中的 NAL單元大小爲65535字節
     (3) Fragmentation unit 一幀數據被分爲多個RTP包,這也是很常見的,特別是對於關鍵幀。現存兩個版本FU-A,FU-B。實際應用就是要加上個H264 STREAM 的頭h264_stream_head = 0x00,0x00,0x00,0x01 4字節,送去解碼即可。

3.分包規則

單個NAL單元包(1-23)

     對於 NALU 的長度小MTU 大小的包, 一般採用單NAL 單元模式.一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload]三部分組成, 其中 Start Code 用於標示這是一個 NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個字節, 其後都是 NALU 單元內容.打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他數據封包的 RTP 包即可。

     一個封裝單個NAL單元包到RTP的NAL單元流的RTP序號必須符合NAL單元的解碼順序。單個NAL單元包的結構顯示如圖。(NAL單元的第一字節和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          |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

    一個包就是一幀數據。h264_stream_head + NAL_unit_type... 就可以直接送去解碼了。 

組合包(24-27)

  單時間組合包(24-25)

       STAP應該用於當組合在一起的NAL單元共享相同的NALU時刻。STAP-A(24)荷載不包括DON,至少包含一個單時刻組合單元. STAP-B(25)荷載包含一個16位的無符號解碼順序號(DON) (網絡字節序)緊跟至少一個單時刻組合單元.

       DON域指定STAP-B傳輸順序中第一個NAL單元的DON值. 對每個後續出現在STAP-B中的NAL單元,它的DON值等於(STAP-B中前一個NAL的DON值+1)%65535, %是取模運算。

       單時刻組合單元有一個16位無符號大小信息(網絡字節序),它指示後續NAL單元的大小(以字節爲單位)(不包括這兩個字節,但包括NAL單元類型字節),後面緊跟NAL單元本身, 包括它的NAL單元類型字節. 單時刻聚合單元在RTP荷載中是字節對齊的,但是可以不是32位字邊界對齊。

       STAP-A:一個RTP包包含一個STAP-A. STAP包含兩個單時刻組合單元:

      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         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

     STAP-B:一個RTP包包含一個STAP-B. STAP包含兩個單時刻組合單元:

       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-B NAL HDR |              DON                           | NALU 1 Size   |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | NALU 1 Size   | NALU 1 HDR    | NALU 1 Data                              |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                                   +
      :                                                                                                         :
      +                         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           | NALU 2 Size                   | NALU 2 HDR              |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                    NALU 2 Data                                 |
      :                                                                                                          :
      |                                                     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                      :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

        看這個結構應該很清楚了,先是16位的長度,就可以得到一幀,h264_stream_head + NALU 1 HDR...送去解碼。再算下一幀。需要注意的這個NALU Size 是不包括他本身這2個字節。STAP-B還要考慮DON。

   多時間組合包(26-27)

        多時刻時間包的NAL單元荷載有16位的無符號解碼順序號基址(DONB) (網絡字節序)以及一個或多個多時刻聚合單元,DONB 必須包含MTAP中NAL單元的第一個NAL的DON的值。

        NAL解碼順序中的第一個NAL單元不必要是封裝在MTAP中的第一個NAL單元

        兩個多時刻組合單元都有16位的無符號大小信息用於後續NAL單元(網絡字節序),一個8位無符號解碼序號差值(DOND), 和n位 (網絡字節序) 時戳位移(TS 位移)用於本NAL單元,n可以是16/24. 不同MTAP類型的選擇是應用相關的時戳位移越大, MTAP的靈活性越大, 但是負擔也越大。

         MTAP16/MTAP24多時刻組合單元的結構如圖示。

MTAP16:
       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      :        NAL unit size                  |      DOND                 |  TS offset      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  TS offset          |                                                                              |
      +-+-+-+-+-+-+-+-+              NAL unit                                                  |
      |                                                                                                         |
      |                                                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                    :
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

MTAP24:
       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      :               NALU unit size             |          DOND        |   TS offset      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |         TS offset                             |                                                    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                                   |
      |                                                NAL unit                                           |
      |                                                   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                    :
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

        一個包中的組合單元的開始/結束不要求位於32位的邊界。跟隨NAL單元的DON 等於(DONB + DOND) % 65536,  %代表取摸操作. 本文沒有指定MTAP內的NAL單元如何排序,但大多數情況,應該使用NAL單元解碼順序。

        時戳位移域必須設置成等於以下公式的值:如果NALU-time大於等於包的RTP時戳,則時戳位移等於(NALU-time - 包的RTP時戳).如果NALU-time小於包的RTP時戳,則時戳位移等於 NALU-time + (2^32 - 包的RTP時戳)。

(1)一個RTP包包含一個多時刻MTAP16類型的組合包,包括兩個多時刻組合單元 

       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                                         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |MTAP16 NAL HDR | decoding order number base  | NALU 1 Size |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  NALU 1 Size     |  NALU 1 DOND       |       NALU 1 TS offset        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  NALU 1 HDR   |  NALU 1 DATA                                                      |
      +-+-+-+-+-+-+-+-+                                                                             +
      :                                                                                                         :
      +                         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           | NALU 2 SIZE                   |         NALU 2 DOND  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       NALU 2 TS offset       |  NALU 2 HDR   |       NALU 2 DATA      |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                         |
      :                                                                                                         :
      |                                                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                     :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

(2)一個RTP包包含一個多時刻MTAP24類型的組合包,包括兩個多時刻組合單元

       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                                        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |MTAP24 NAL HDR |  decoding order number base | NALU 1 Size |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  NALU 1 Size   | NALU 1 DOND |       NALU 1 TS offs                    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |NALU 1 TS offs |  NALU 1 HDR   |      NALU 1 DATA                       |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                                                   +
      :                                                                                                         :
      +                         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           | NALU 2 SIZE                   |         NALU 2 DOND  |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |       NALU 2 TS offset                                  |          NALU 2 HDR    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |  NALU 2 DATA                                                                                 |
      :                                                                                                         :
      |                                                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                     :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

       看這個結構應該很清楚了,先是16位的DONB,然後是16位的長度,8位的DOND,根據DONB計算出DON,去掉時間戳(16-24bits),就可以得到一幀,h264_stream_head + NALU 1 HDR...。得到該RTP包中所有的NAL單元后,根據DON確定解碼順序。需要注意的這個NALU Size 是不包括他本身這2個字節。

    分片單元 (FUs)(28-29)

       當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包,NAL單元的一個分片由整數個連續NAL單元字節組成. 每個NAL單元字節必須正好是該NAL單元一個分片的一部分。相同NAL單元的分片必須使用遞增的RTP序號連續順序發送(第一和最後分片之間沒有其他的RTP包)。相似, NAL單元必須按照RTP順序號的順序裝配。

       當一個NAL單元被分片運送在分片單元(FUs)中時,被引用爲分片NAL單元。STAPs,MTAP不可以被分片。 FUs不可以嵌套,即,一個FU 不可以包含另一個FU. 運送FU的RTP時戳被設置成分片NAL單元的NALU時刻.

       FU-A的RTP荷載格式。FU-A由1字節的分片單元指示1字節的分片單元頭,和分片單元荷載組成。

       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        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      FU-B的RTP荷載格式. FU-B由1字節的分片單元指示,1字節的分片單元頭,和解碼順序號(DON)以及分片單元荷載組成。

       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     |                         DON                 |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                                                                         |
      |                                               FU payload                                        |
      |                                                                                                         |
      |                                                    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                     :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 

       對於分片NAL單元的第一個分片如果用於交錯打包方式,則必須使用NAL單元類型FU-B。NAL單元類型FU-B MUST不可以用於其他情況。換句話, 在交錯打包方式,每個被分片的NALU,FU-B作爲第一個分片,後面跟隨的是一個或多個FU-A分片。

       FU指示字節有以下格式:

      +--------------------+
      |0 |1|2 |3|4| 5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|    Type    |
      +--------------------+

       FU指示字節的類型域的28,29表示FU-A和FU-B。NRI域的值必須根據分片NAL單元的NRI域的值設置。

       FU頭的格式如下:

      +--------------------+
      |0 |1|2 |3|4 |5|6|7|
      +-+-+-+-+-+-+-+-+
      |S|E|R|    Type    |
      +--------------------+

      S:1 表示是一幀的開始包

      E:1 表示是一幀的結束包,和RTP marker位一致

      R:0 必須

      這裏要注意一下,組包時,NAL unit type 必須自己拼裝FU Indicator前四字節+ FU Header後四字節。也就是type字段是 FU header裏的nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)等幀收齊了,加上H264_streaming_head + nal_unit_type....送去解碼。(上述部分內容來源於網絡)

二、數據分析

首先看一下序列參數集sps、圖像參數集pps的處理方式:

{0x80, 0x60, 0x00, 0x01, 0x05, 0xac, 0x32, 0xf8, 0x11, 0xe1, 0xa6, 0x6a, 0x67, 0x42, 0x00, 0x29, 
0x8d, 0x8d, 0x40, 0x3c, 0x01, 0x13, 0xf2, 0xcd, 0x41, 0x40, 0x80, 0x81, 0xe1, 0x10, 0x8d, 0xc0}

紅色部分爲RTP頭,這部分在解析H264時可以暫時不用處理,先忽略掉。後面第一個字節爲0x67,PayLoadType=0x67 & 0x1F,計算後通過表1可以看到爲sps,在處理這部分時只需要去掉RTP頭部,在前面加上00 00 00 01四個字節後直接寫入緩存。

{0x80, 0x60, 0x00, 0x02, 0x05, 0xac, 0x32, 0xf8, 0x11, 0xe1, 0xa6, 0x6a, 0x68, 0xca, 0x43, 0xc8}

同樣,根據sps的分析過程,該幀爲pps,處理方式與sps一樣即可。

{0x80, 0x60, 0x00, 0x03, 0x05, 0xac, 0x32, 0xf8, 0x11, 0xe1, 0xa6, 0x6a, 0x7c, 0x85, 0x88, 0x80, 
0x00, 0x40, 0x00, 0x00, 0xa7, 0xff, 0xff, 0xc5, 0xc5, 0x00, 0x02, 0xbf, 0xc0, 0x03, 0xdb, 0x8a,  截取了一部分數據。

紅色部分爲RTP頭,後面一個字節0x7C爲分片單元指示,0x85爲分片單元頭。

0x7C & 0x1F = 28(FU-A類型) ,0x85的二進制爲:1000 0101‬

       1                       0                    0              0 0 1 0 1

開始標誌(1)      結束標誌(0)          0            NALType(5)

通過分析可以看到數據包爲FU-A類型,該分片是一幀的開始,而且是關鍵幀。在處理FU-A時,上面已經介紹了方法,再來計算一下NAL unit type= 0x7C & 0xE0 | NALType,爲0x65,在組包時需要把RTP頭、分片單元指示字節和分片單元頭字節去掉,在前面加上0x00 0x00 0x00 0x01 0x65字節然後存入緩存即可。

{0x80, 0x60, 0x00, 0x04, 0x05, 0xac, 0x32, 0xf8, 0x11, 0xe1, 0xa6, 0x6a, 0x7c, 0x05, 0xea, 0x3f, 
0x09, 0xf3, 0xda, 0x7f, 0x57, 0x7f, 0xa7, 0xf5, 0xff, 0xfb, 0xe2, 0xba, 0xdd, 0x77, 0xd2, 0xff, 截取了一部分數據。

紅色部分爲RTP頭,後面一個字節0x7C爲分片單元指示,0x05爲分片單元頭。

0x7C & 0x1F = 28(FU-A類型) ,0x05的二進制爲:0000 0101‬

       0                       0                    0              0 0 1 0 1

開始標誌(0)      結束標誌(0)          0            NALType(5)

通過分析可以看出該包爲中間包,處理方式比較簡單,去掉RTP頭、分片單元指示分片單元頭,繼續存入緩存中即可。

{0x80, 0xe0, 0x00, 0x2c, 0x05, 0xac, 0x32, 0xf8, 0x11, 0xe1, 0xa6, 0x6a, 0x7c, 0x45, 0x1c, 0x67, 
0xba, 0x5a, 0x9a, 0x2e, 0x6a, 0x73, 0x98, 0xfa, 0x99, 0x8b, 0x86, 0x2f, 0xcf, 0xf1, 0x4c, 0x5b,截取了一部分數據。

紅色部分爲RTP頭,後面一個字節0x7C爲分片單元指示,0x45爲分片單元頭。

0x7C & 0x1F = 28(FU-A類型) ,0x45的二進制爲:0100 0101‬

       0                       1                    0              0 0 1 0 1

開始標誌(0)      結束標誌(1)          0            NALType(5)

通過分析可以看出該包爲結束包,處理方式比較簡單,去掉RTP頭、分片單元指示分片單元頭,繼續存入緩存中即可。

到此一幀數據提取完畢,就可以送給ffmpeg解析了。

三、使用ffmpeg解碼H264

在使用ffmpeg解碼時,需要循環接收你提取的H264數據,然後再進行解析即可。

int pos = 0;
do
{
    uint8_t *poutBuf;
    int pout_len;
    int len = av_parser_parse2(m_pCodecParserContext, m_pCodecContext, 
		&poutBuf, &pout_len, (uint8_t*)pData + pos, nLength - pos,
		AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
    pos += len;
    if (pout_len > 0)
    {
        AVPacket packet;
	av_init_packet(&packet);
	packet.data = poutBuf;
	packet.size = len ;
	packet.pts = 90000/25 * Count++;
	int ret = -1;
	ret = avcodec_send_packet(m_pCodecContext, &packet);
	if (ret < 0)
	{
	    continue;
	}
	while (!ret)
	{
		ret = avcodec_receive_frame(m_pCodecContext, m_pSrcFrame);
		if (!ret)
		{
			msleep(20);
			int w = m_pCodecContext->width;
			int h = m_pCodecContext->height;
			if (m_pRGBSwsContext == NULL)
			{
				m_pRGBSwsContext = sws_getContext(w, h, m_pCodecContext->pix_fmt, w, h, AV_PIX_FMT_RGB32, SWS_BICUBIC, NULL, NULL, NULL);
				av_image_alloc(m_pFrameRGB->data, m_pFrameRGB->linesize, w, h, AV_PIX_FMT_RGB32, 1);
			}
			sws_scale(m_pRGBSwsContext, (uint8_t const * const *)m_pSrcFrame->data, m_pSrcFrame->linesize, 0, h, m_pFrameRGB->data, m_pFrameRGB->linesize);
			//把這個RGB數據 用QImage加載
			QImage tmpImg((uchar *)m_pFrameRGB->data[0], m_pCodecContext->width, m_pCodecContext->height, QImage::Format_RGB32);
			QImage image = tmpImg.copy();
			//把圖像複製一份 傳遞給界面顯示
			emit signal_sendQImage(image);
			av_frame_unref(m_pSrcFrame);
		}

	}
    }
}

這是使用Qt + VS開發的,視頻能夠正常播放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章