RTP载荷H264视频流
? ? ??視頻:
? ? ? ? ? ? ?由一副副連續的圖像構成,由于數據量比較大,因此為了節省帶寬以及存儲,就需要進行必要的壓縮與解壓縮,也就是編解碼。
? ? ??h264裸碼流:
? ? ? ? ? ? ?對一個圖像或者一個視頻序列進行壓縮,即產生碼流,采用H264編碼后形成的碼流就是h264裸碼流。
? ? ??碼流傳輸:
? ? ? ? ? ? ?發送端將H264裸碼流打包后進行網絡傳輸,接收端接收后進行組包還原裸碼流,然后可以再進行存儲,轉發,或者播放等等相關的處理。
? ? ? ? ? ? ?存儲轉發可以直接使用裸碼流,播放則需要進行解碼和顯示處理
? ? ??解碼顯示:? ? ? ?
? ? ? ? ? ? ?一般會解成YUV數據,然后交給顯示相關模塊做處理,如使用openGL或者D3D等進行渲染(采用3d的方式來顯示2d的圖像稱為渲染)
? ? ? ? ? ? ? 解碼又分軟件解碼和硬件解碼,
? ? ? ? ? ? ? 軟解一般ffmpeg
? ? ? ? ? ? ? 硬解則各不同,由各硬件廠商開放sdk來處理,如:hisi,intel media sdk,nvida gpu,apple ios videotoolbox等。
??
? ? ? 類似發送網頁文本數據有http一樣,視頻數據在網絡上傳輸也有專門的網絡協議來支持,如:rtsp,rtmp等
? ? ? 由于碼流是一幀一幀的圖片數據,所以傳輸的時候也是一幀幀來傳輸的,因此這里就會涉及到各種類型的幀處理了
? ? ? ? ? ? ? ? ? ? ? ? ? ? I 幀: 參考幀或者關鍵幀,可以理解為是一幀完整畫面,解碼時只需要本幀數據就解碼成一幅完整的圖片,數據量比較大。
? ? ? ? ? ? ? ? ? ? ? ? ? ? P幀: 差別幀,只有與前面的幀或I幀的差別數據,需要依賴前面已編碼圖象作為參考圖象,才能解碼成一幅完整的圖片,數據量小。
? ? ? ? ? ? ? ? ? ? ? ? ? ? B幀: 雙向差別幀,也就是B幀記錄的是本幀與前后幀的差別,需要依賴前后幀和I幀才能解碼出一幅完整的圖片,數據量小。
? ? ? 由于i幀比較大,已經超出mtu最大1500,所以需要拆包分片傳輸,這里說的拆包發送不是指發送超過1500的數據包時tcp的分段傳輸或者upd的ip分片傳輸,而是指rtp協議本身對264的拆包。
? ? ? rtp打包后將數據交給tcp或者upd進行傳輸的時候就已經控制在1500以內,這樣可以提高傳輸效率,避免一個I幀萬一丟失就會造成花屏或者重傳造成延時卡頓等等問題。
? ? ? (順便提一句,rtmp打包就比較簡單,由于是基于tcp的協議,大包直接交給tcp去做分段傳輸,rtmp通過設置合適的trunk size去發送一幀幀數據)
? ? ? 既然要進行拆包發送與接收,就少不了需要相關的包結構以及打包組包了,繼續。。。。。。
? ? ? ? ? ? ? ? ? ? ? ? ? ??
? ? ? ? NALU結構:NALU header(1byte) +?NALU payload
? ? ? ? header 部分可以判斷類型等信息,從右往左5個bit位
| SPS:? 0x67? ? header & 0x1F = 7? | I Frame: 0x65??header & 0x1F = 5? |
| PPS:? 0x68? ? header & 0x1F = 8?? | P Frame: 0x41? ?header & 0x1F = 1 |
| SEI:? 0x66? ? header & 0x1F = 6 | ? |
? ? ? ??payload 部分可以簡單理解為 編碼后的264幀數據? ? ??
? ? ? ??詳細可以去查閱?h264 NALU 語法結構
? ? ??
下面是 RFC 3550 中規定的 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
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |V=2|P|X|? CC?? |M|???? PT????? |?????? sequence number???????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????????????????????? timestamp?????????????????????????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????? synchronization source (SSRC) identifier??????????? |
????? +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
????? |??????????? contributing source (CSRC) identifiers???????????? |
????? |???????????????????????????? ....????????????????????????????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
? 負載類型 Payload type (PT): 7 bits
? 序列號 Sequence number (SN): 16 bits
? 時間戳 Timestamp: 32 bits
??rtp打包h264,包含了三種類型的包:
?
?一個rtp包攜帶了一幀數據(single)
?多個rtp包攜帶了一幀數據(FU-A)
?一個rtp包攜帶了多幀數據(STAP-A)
?
?
在實際應用中絕大部分采用的是前兩種方式,對方式1常見的是對nalu的sps,pps進行打包,因為sps和pps數據量很小,一個rtp包足以攜帶,一般采用 sps,pps分別由一個rtp包攜帶的方式。對IDR數據及其他類型數據通常是采用方式2,因為視頻幀數據通常比較大,一個rtp包不足以攜帶,分成多個rtp包攜帶,分包攜帶后對最后一個rtp包的mark字段是要設置為true的。包格式定義詳細見 ?? rfc3984
? H.264 Payload 格式定義了三種不同的基本的負載(Payload)結構.?接收端可通過?RTP Payload?的第一個字節來識別它們. 這一個字節類似 NALU 頭的格式, 而這個頭結構的 NAL 單元類型字段則指出了代表的是哪一種結構。這個字節的結構如下, 可以看出它和 H.264 的 NALU 頭結構是一樣的:
????? +---------------+
????? |0|1|2|3|4|5|6|7|
????? +-+-+-+-+-+-+-+-+
????? |F|NRI|? Type?? |
????? +---------------+
? 字段 Type: 這個 RTP payload 中 NAL 單元的類型.?
??這個字段和 H.264 中類型字段的區別是, 當 type?的值為 24 ~ 31 表示這是一個特別格式的 NAL 單元, 而 H.264 中, 只取 1~23 是有效的值.
一句話:?h264僅用1-23,24以后的用在RTP H264負載類型頭中
???
不同類型的NALU的重要性指示如下表所示:
?
? 24??? STAP-A?? 單一時間的組合包
? 25 ?? STAP-B?? 單一時間的組合包
? 26??? MTAP16?? 多個時間的組合包
? 27??? MTAP24?? 多個時間的組合包
? 28??? FU-A???? 分片的單元
? 29??? FU-B???? 分片的單元
? 30-31 沒有定義
?
? 可能的結構類型分別有:
? 1. 單一 NAL 單元模式
???? 即一個 RTP 包僅由一個完整的 NALU 組成.?這種情況下 RTP NAL 頭類型字段和原始的 H.264的?NALU 頭類型字段是一樣的.
? 2. 組合封包模式
??? 即可能是由多個 NAL 單元組成一個 RTP 包. 分別有4種組合方式: STAP-A, STAP-B, MTAP16, MTAP24.
??那么這里的類型值分別是 24, 25, 26 以及 27.
? 3. 分片封包模式
??? 用于把一個 NALU 單元封裝成多個 RTP 包. 存在兩種類型 FU-A 和 FU-B.?類型值分別是 28 和 29.
?
? ? ? ? ? ? ? ?1.? 單NALU:? ?P幀或者B幀比較小的包,直接將NALU打包成RTP包進行傳輸? ??RTP header(12bytes) +?NALU header?(1byte)?+?NALU payload
? ? ? ? ? ? ? ?2.? 多NALU:? ?特別小的包幾個NALU放在一個RTP包中??
? ? ? ? ? ? ? ?3.? FUs(Fragment Units):? ?I幀長度超過MTU的,就必須要拆包組成RTP包了,有FU-A,FU-B
? ? ? ? ? ? ? ? ? ??RTP header?(12bytes)+?FU Indicator?(1byte)? +??FU header(1 byte) +?NALU payload
? ? ? ? ? ? ? ? ? ? ? ? ?看到這里會不禁思考,
? ? ? ? ? ? ? ? ? ? ?1.?NALU頭不見了,如何判斷類型?實際上NALU頭被分散填充到FU indicator和FU header里面了
? ? ? ? ? ? ? ? ? ? ? ? ?bit位按照從左到右編號0-7來算,nalu頭中0-2前三個bit放在FU indicator的0-2前三個bit中,后3-7五個bit放入FU header的后3-7五個中? ? ??
//NALU header = (FU indicator & 0xe0) | (FU header & 0x1F)? ?取FU indicator前三和FU header后五? headerStart[1] = (headerStart[0]&0xE0)|(headerStart[1]&0x1F); ??因此查看I幀p幀類型,遇到FU分片的,直接看第二個字節,即Fu header后五位,這個跟直接看NALU頭并無差異,一般有:0x85,0x05,0x45等等
? ? ? ? ? ? ? ? ? ?2.??多個RTP包如何還原組合成回一個完整的I幀? 在FU header中有標記為判斷
? ? ? ? ? ? ? ? ? ? ? ? ?照舊從左到右,Fu header前兩個bit表示start和end標記,start為1表示一個i幀分片開始,end為1表示一個i幀分片結束
? ? ? ? ? ? ? ? ? 3.? ?如何查看是一個I幀分片開始?? ?
? ? ? ? ? ? ? ? ? ? ? ? 看第一個字節FU Indicator,照舊從左到右,Fu Indicator前三個bit是NALU頭的前三個bit,后五位為類型FU-A:28(11100),FU-B:29(11101)
? ? ? ? ? ? ? ? ? ? ? ? ?RTP抓包看下來整個字節是0x7c開頭
? ? ? ? ? ? ? ? ? ? ? ? ?如果不是分片,第一字節就是NALU頭,如:0x67,0x68,0x41等
?
? ? ? ? --->RTP包中接收的264包是不含有0x00,0x00,0x00,0x01頭的,這部分是rtp接收以后,另外再加上去的,解碼的時候再做判斷的。
? ? ? 1. SPS
? ? ? ?
? ? ?2.??I幀分片開始,第一個字節FU Indicator,0x7c, 后五位11100,28,FU-A
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 第二個字節FU Header,0x85,前兩個bit start位1,end位0 表示 分片開始,后五個bit值5,I幀
? ? ? ??
? ? ? ??I幀分片,0x7c開頭,第二個字節0x05,?FU Header start和end位 0,后五個bit值5,I幀
? ? ? ? ?
? ? ? ??I幀分片結束,7c開頭,第二個字節0x45,FU Headr,start 0,end1,后五個bit值5,I幀, Mark標記一幀結束
? ? ? ? ??
?
? ? 3.? p幀,第一個字節:0x41
? ? ? ? ??
?
? ? ? ?4.?P幀分片開始:第一個字節FU Indicator,0x7c, 后五位11100,28,FU-A
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?第二個字節FU Header,0x81,?前兩個bit start位1,end位0 表示 分片開始,后五個bit 值是1,p幀
? ? ? ? ? ?
? ? ? ? ???P幀分片結束:0x5c開頭,第二個字節0x41,FU Headr,start 0,end1,后五個bit值1,P幀, Mark標記一幀結束
? ? ? ? ?
?
? 下面描述了如何在 SDP 中表示一個 H.264 流:
? . "m=" 行中的媒體名必須是 "video"
? . "a=rtpmap" 行中的編碼名稱必須是 "H264".
? . "a=rtpmap" 行中的時鐘頻率必須是 90000.
? . 其他參數都包括在 "a=fmtp" 行中.
? 如:
? m=video 49170 RTP/AVP 98
? a=rtpmap:98 H264/90000
? a=fmtp:98 profile-level-id=42A01E; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
? 下面介紹一些常用的參數.
?
? 表示支持的封包模式.?
? 當 packetization-mode 的值為 0 時或不存在時, 必須使用單一 NALU 單元模式.
? 當 packetization-mode 的值為 1 時必須使用非交錯(non-interleaved)封包模式.
? 當 packetization-mode 的值為 2 時必須使用交錯(interleaved)封包模式.
? 這個參數不可以取其他的值.
?
?
? 這個參數可以用于傳輸 H.264 的序列參數集和圖像參數 NAL 單元. 這個參數的值采用 Base64 進行編碼. 不同的參數集間用","號隔開.
??
? 這個參數用于指示 H.264 流的 profile 類型和級別. 由 Base16(十六進制) 表示的 3 個字節. 第一個字節表示 H.264 的 Profile 類型, 第
?
三個字節表示 H.264 的 Profile 級別:
??
? 這個參數的值是一個整型, 指出了每一秒最大的宏塊處理速度.
?
參考:
https://www.cnblogs.com/leehm/p/11009504.html
https://blog.csdn.net/mo4776/article/details/78391969
https://www.cnblogs.com/stnlcd/p/7266797.html
https://blog.csdn.net/bytxl/article/details/50393198
總結
以上是生活随笔為你收集整理的RTP载荷H264视频流的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [vue] 你有写过自定义组件吗?
- 下一篇: Charles使用手册