rtmp官方標準規範詳細解析

標準規範學習:

rtmp消息結構,包括幾個部分:
時戳:4  byte,單位毫秒。超過最大值後會翻轉。
長度:消息負載的長度。
類型ID:Type Id 一部分ID範圍用於rtmp的控制信令。還有一部分能夠供上層使用,rtmp只是透傳。這樣能夠方便的在rtmp上進行擴展。
消息流ID:Message Stream ID,用於區分不一樣流的消息。
 
兩個ID的區別:
Message stream:傳輸消息的邏輯通道。
Message stream ID:每一個消息都有一個流id,用於指明屬於哪一個流。
 
Chunk:是更底層的一個概念。Message有可能過大,須要分割成一個個碎片,chunk就是一個消息的部分碎片。
Chunk stream:傳輸chunk的邏輯通道。
Chunk stream ID:用於標示chunk屬於哪一個邏輯通道。
message stream和chunk stream應該屬於不一樣的層次,message屬於應用層次消息,chunk屬於更底層rtmp協議層次。
一個chunk stream 上可以跑多個message stream。message stream id在一個chunk stream下要不相等。
 
消息會切分紅一個個小的塊進行傳輸。
 
rtmp的時戳單位是毫秒。
鏈接握手流程圖:
握手過程:服務器和客戶端各自發送三個包:c0,c1,c2,s0,s1,s2,服務器必須在收到c0後才發送s0和s1,也能夠等到c1才發送;服務端必須收到c1纔可以發送s2,客戶端必須收到s2纔可以發送c2
 
c0和s0就是一個字節:表示協議版本號。如今是03。
01 234567
+-+-+-+-+-+-+-+-+
|    version    |
+-+-+-+-+-+-+-+-+
  C0 and S0 bits
 
c1和s1長度1536,
抓包發現,zero字段不必定爲0。
 
c2和s2的長度也是1536
經過vlc和nginx rtmp抓的包發現和規範不對應。安裝規範,time和time2應該是爲了計算帶寬和延遲。
 
 
交互過程:
通常客戶端一塊兒發生c0和c1,而後服務器直接發送s0,1,2。客戶端收到後發送c2,握手完成。三次交互就能夠了。
 
塊流:

一個鏈接能夠穿輸多個塊流。每一個塊流有不一樣的id來區分。
塊傳輸運行將大的消息包切割爲小的消息包。防止大的數據好比視頻阻塞鏈接,致使音頻和信令也沒法傳遞。
小的消息也能夠成本更加低的傳輸,包頭會壓縮.
 
塊流大小能夠配置。有一個消息:set chunk size能夠協商大小。大的塊能夠下降cpu 負載,可是可能會阻塞重要消息;小的塊不利於傳輸,特別是在低帶寬的狀況下。
 
塊容許 層協議將大的消息 解 更小的消息,例如,防 體積大的但優先級小的消 息 (好比視頻) 阻礙體積較小但優先級高的消息 (好比音頻或者控制命 ) ——傳送過程,音頻和控制的優先級較高。
 
塊的大小是  配置的 它  使用一個設置塊大小的控制消息 行設置 (參考 5.4.1) 更大的塊大小  降  CPU 開銷,但在  寬 接時因 它的大量的寫入也會延   他內容的傳遞 更小的塊不利於高比特率的流化 所 塊的大小設置 決於 體狀況。 ——這是使用tcp必需要考慮的問題。塊過大會影響音頻和控制的發送。太小會影響效率和比特率。
 
塊類型:
 
塊基本頭:
 

 
page12image7536
 
第一個字節都是這樣。其中fmt用來指示Message Header。
cs id:
cs id是chunk stream id的縮寫。範圍是3——65599。可變字節,後面能夠跟一個字節,也能夠跟兩個字節。跟幾個字節是有第一個字節的後面6位的值決定的。這一點中文翻譯寫的不完整。
若是最後6位值爲0,則表示後面只有一個字節。id範圍是64——319,其實就是0——255,最大和最小加64。
page13image384
若是最後6位值爲1,則表示後面只有兩個字節。 id範圍是64 - 65599,其實就是0——65535, 最大和最小加64。j
計算方法比較特殊:(第三 個 節) * 256 + 第二 個 節 + 64
page13image7080
 
塊流id應該是區分每個流,好比,一個視頻通話,包括視頻和音頻兩個流。這裏的意思應該是一個鏈接能夠傳遞多個流,經過塊流id進行區分。
 
塊消息頭

塊消息頭格式由塊基本頭的fmt字段決定。共四種。
 
fmt:
四種類型:0 1 2 3
包頭必須儘量的壓縮。
 
type 0:用在流開始,或者時戳重置的時候。message header消息頭共11byte。
三字節時戳:表示範圍爲0——16777215(0xffffff),若是大於等於16777215,則表示還有一個字節的擴展時戳。chunk header的第三部分就是extend timestamp。這一本部分是否存在由三個字節的值決定。 注意,這個是絕對時戳,然後面的幾種類型trunk都是時戳的增量;區分消息截止是根據消息的長度來進行的。那麼輸入處理主動丟棄包的狀況?
 
 
 
type 1:message header有7byte,比type 0少了4個字節的message stream id,使用上一個塊的id。大小可變的消息(好比視頻的每一幀數據)每每會在第一幀(第一幀的第一個chunk須要用type0)後面的幀的第一個chunk中使用type1。爲何?由於可變數據,必須有長度信息記錄。
 
type2:只有三個字節。沒有message stream id和message 長度。所有使用同一個chunk stream的上一個chunk的。適用於長度不變的步伐傳輸。
 
type 3:0個字節的message header。時戳,長度,消息流id所有使用同一個chunk stream的上一個chunk。當一個消息切分後劃分到多個chunk的時候,除了帶個chunk,全部的其餘chunk應該使用type3。——如何判斷包結束?根據消息的長度,第一個chunk中的長度應該是一個消息完成的長度。
 
四種格式的使用:
第一個消息的第一個chunk 使用type0,攜帶所有的信息;後面的chunk使用type3;
第二個消息,若是是視頻消息,長度可變,則第一個chunk使用type1,值丟棄message stream id便可。第二個消息的其餘chunk使用type3。
 
若是是音頻,且長度相同,則第一個消息用type0+type3,第二個消息用type2+type3。
若是音頻消息,長度,消息間時戳增量(delta)都相同,則第一個消息能夠用type0+type3,後面的全部消息所有用type3便可。這樣的話也要求第一個消息的時戳必須和消息間的時戳增量相同。
 
 
注意:除type0外,其餘的所有是時戳的增量。而不是時戳絕對值。
從上面來看,音頻和視頻的chunk id應該是不同的。不然沒法區分。由於有些塊是沒有message stream id,只有chunk stream id的。
 
公共字段定義:
一、timestamp delta:表示的是上一個chunk 和當前chunk的時戳差。不是消息的時間差。若是大於等於16777215,則表示還有一個字節的擴展時戳。chunk header的第三部分就是extend timestamp。
二、消息長度:消息的長度。他和chunk的payload的大小是不一樣的。chunk size length是全部chunk的大小再加最後一個大小。——消息長度是消息實際的大小。。
三、message type id:標示消息類型,好比音頻,視頻,控制等。
四、message stream id:以小端序存儲。
Extended Timestamp:當時戳大於
 
play2:能夠實現比特率的切換。
 
message length,chunk size,tcp分包和消息的切割

終於弄明白其中的原理了。原本這幾個概念和方法在規範中描述不是很清楚,結合抓包終於弄清楚 了。
message length:及時消息自己的大小。這個消息要在chunk中進行傳輸。
chunk size:chunk的大小。chunk的大小默認是128。能夠經過消息設置chunk size 的最大值。每一個chunk的大小最大不可以超過max chunk size。
明白上面兩點後進行分析:
一、若是message length小於等於max chunk size,則一個chunk中就包含着一個message。
二、若是message length大於max chunk size,則須要將這個message切分爲多個chunk。前面幾個chunk size必須是max 
size,最後一個就是剩餘的大小。
 
tcp分包過程:
一、收到chunk,明確chunk stream id,對一個chunk stream的數據進行處理。
二、判斷fmt類型,肯定消息長度。
三、若是長度小於等於max chunk size,則這個chunk body的大小就是message length。
四、處理完這個chunk,跳過chunk header 和chunk body,就是下一個chunk。
五、若是長度大於max chunk size,則chunk body的大小就是max chunk size。處理這一部分數據,而後跳過max chunk size找到下一個chunk的頭。有消息長度減去max chunk size計算剩餘的數據長度,判斷剩餘長度是否大於max chunk size,若是大於,則代表這個chunk 大小仍是max chunk size。以此類推,直到最後一個長度小於等於max chunk size,那麼這個長度就是這個chunk的實際長度,而且是這個消息的最後一個消息切片。而後把全部的有效切片拼接起來,就是完整的消息。後面收到的將是另一個消息。
 
協議控制消息:

RTMP使用1,2,3,4,5,6的message type id做爲控制消息。控制協議的message stream id必須是0, chunk stream id必須是2(2的做用。0,1用來表示字節個數,2是信令,3-6xxxx是實際的。)。控制信令一收到就生效——就是沒有協商過程。。。——時戳能夠忽略。
 
set chunk size (1):設置chunk的最大size

message type id 爲1。共四個字節:
第一位必須爲0。
 
默認值是128,服務端和客戶端均可以設置chunk size。注意,一個交互中chunk size是相互獨立的,也就是,客戶端能夠設置他發送過去的chunk size,服務端也能夠設置他發送過去的chunk size。兩個是沒有影響的。
chunk size最小建議128,必須大於等於1。
chunk size的範圍是1到0x7fffffff(2147483647),可是由於message header中message length只有三個字節,因此chunk size的最大值是16777215  若是大於此,就去他。
 
Abort Message (2)

message type id爲2,四個字節,攜帶的內容是chunk stream id。用於通知對端,若是這個chunk stream還有消息正在等待接收未到達的消息內容,則中止,並丟棄原先接受的內容。能夠用在帶寬有限是優先發送音頻和信令,丟棄視頻。
 
Acknowledgement (3) Window Acknowledgement Size (5)

Window Acknowledgement Size用於設置窗口確認大小,Acknowledgement是窗口確認消息。
會話開始時,雙方都要先對端發送Window Acknowledgement Size,用於指明指望得到確認的大小。當一端收到內容大小超過Window Acknowledgement Size,就要像對方發送Acknowledgement。
一、會話開始計算收到byte個數的時間點是收到Window Acknowledgement Size消息開始。
二、byte size不包括tcp包頭,應該是chunk的大小,即從tcp 的recv函數中得到的內容大小。
三、雙方都要向對方發送Window Acknowledgement Size和Acknowledgement。
四、發送端發送完Window Acknowledgement Size消息後,沒有收到Acknowledgement是再也不發送進一步的消息的——這樣會容易引發錯誤,致使再也發送不出消息了。
 
 
Set Peer Bandwidth (6)

 
設置對端輸出帶寬。對端是經過設置Window Acknowledgement Size來實現流量控制的。超過Window Acknowledgement Size後未確認發送端將再也不發送消息。因此對端收到set peer bandwidth後,若是以前發送的Window Acknowledgement Size和這裏寫的的Window Acknowledgement Size不同,通常會發送一個Window Acknowledgement Size。
 
 
message format

 
上面的協議控制消息的type id是1,2,3,5,6(這些是chunk stream的控制),沒有4。4是另一個類型:
User Control Messages (4):用戶控制協議,是RTMP stream的控制協議。 一樣,chunk stream id要設置爲2,message stream id要設置爲0。
 
消息體格式:兩個字節的event type,後面跟可變長度的event data,
 
RTMP Command Messages

客戶端和服務器之間能夠發送的消息包括:音頻消息,視頻消息,數據消息,命令消息。命令消息採用AMF編碼。
 
command message type 20,17表示是命令消息。20表示使用AMF0編碼,17表示使用AMF3編碼。
命令消息包括connect, createStream, publish, play, pause ,響應消息使用onstatus,result。
 
Data Message (18, 15):數據消息,用於傳輸Metadata或用戶數據。18表示AMF0,15是AMF3。
 
Shared Object Message (19, 16):19表示AMF0,16是AMF3。
 
Audio Message (8):音頻消息
Video Message (9):視頻消息
 
Aggregate Message (22):一個消息中包含多個消息。
 
Types of Commands( 20,17)

netConnetion 命令:
connect :請求鏈接到服務器的應用實例。
 
call:請求一個遠程調用。
 
creatStream:建立一個邏輯通道,用於客戶端來發送音頻,視頻,描述數據。netConnection是默認通道,message stream id是0,creatStream使用0做爲message stream id。
 
NetStream Commands:
多個Netstream能夠共用一個netconnection。可是stream的id是在何時肯定的???—— 疑問
 
play2:切換到不一樣的比特率的流上,而不用更改播放時間。這是一個有用的功能。這個消息是在paly以後再發送。
 
deleteStream:刪除流。
 
receiveAudio:是否接受音頻。若是爲false,服務器不用回覆。若是爲true,服務器回覆兩個狀態:
NetStream.Seek.Notify and   NetStream.Play.Start
 
receiveVideo:一樣。
 
publish:發佈一個流到server。須要onStatus響應。
 
seek:偏移。毫秒爲單位。
 
pause:暫停。
 
example:
首先,connect是鏈接的服務器端的應用(nginx rtmp有配置多個應用。)
 
視頻裸數據是如何打包進rtmp包的?

ffmpeg在flv和h264文件將的轉換是有問題的。
 
視頻性格的數據包格式和flv的格式很是的像,基本上就是flv格式的變種。參考flv文件格式官方協議詳解。
視頻相關包包括:onMetaData,AVCDecoderConfigurationRecord,h264數據。和flv文件中的區別是flv文件用tag頭,rtmp中相關信息是放在rtmp頭中。至於內部內容是同樣的。
 
 
AMF0編碼格式

  1. *AMF數據類型: 
  2.  *Type      Byte code 
  3.  *Number    0x00 
  4.  *Boolean   0x01 
  5.  *String    0x02 
  6.  *Object    0x03 
  7.  *MovieClip 0x04 
  8.  *Null      0x05 
  9.  *Undefined 0x06 
  10.  *Reference 0x07 
  11.  *MixedArray    0x08 
  12.  *EndOfObject   0x09 
  13.  *Array         0x0a 
  14.  *Date          0x0b 
  15.  *LongString    0x0c 
  16.  *Unsupported   0x0d 
  17.  *Recordset     0x0e 
  18.  *XML           0x0f 
  19.  *TypedObject (Class instance)  0x10 
  20.  *AMF3 data 0×11 
 
amf編碼:對個數據的合集,數據的邊界經過不一樣的類型,以及不一樣類型的長度來區分。
第一個字節是數據類型,而後根據數據類型肯定數據的長度。其中,string是可變長度,兩個字節長度值。
若是是object,則object內部是個字典,key是字符串,value是數據,這裏還要對數據根據類型對數據解析,同上。
 
 

我 的微信公衆號nginx

相關文章
相關標籤/搜索