rtmp的英文官方文檔
http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdfhtml
國人的翻譯
https://blog.csdn.net/noahsun1024/article/details/52177007
https://www.cnblogs.com/shishuo365/p/5862613.html服務器
大多數整數都是大端格式(即網絡字節序), 可是有些是例外的網絡
單位爲毫秒app
chunk stream id 大端字節序, 同一個chunk的數據包必須是有序的, 不能亂. message stream id 有的地方是大端格式, 有些地方是小端格式.
message type id 代表消息體的格式的類型. 這是最須要關注的ID. 這些ID很煩人, 有的消息, 這些ID是規定死的.測試
+--------------+----------------+--------------------+--------------+ | Basic Header | Message Header | Extended Timestamp | Chunk Data | +--------------+----------------+--------------------+--------------+
Basic Header是變長的, 有3種格式
Message Header也是變長的, 有4種格式
Extended Timestamp不必定會出現, 4個字節.net
有三種格式, 本文只說明最簡單的格式 , 另個兩個格式不經常使用. 讀者本身去看文檔翻譯
//一個字節的模式, 存放較小的stream id. (一般stream id都是從3開始的, 一個字節夠了) 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |fmt| chunk stream id +-+-+-+-+-+-+-+-+
fmt用於代表Message Header的格式, 分別爲Type0, Type1, Type2, Type3code
根據fmt的的值, 來決定哪一種類型視頻
0 1 2 3 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp |message length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | message length (cont) |message type id| msg stream id | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | message stream id (4B) (小端) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Chunk Message Header - Type 0
0 1 2 3 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp delta |message length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | message length (cont) |message type id| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
相比於type0, type1省略了stream id, 表示與上一個chunk的stream id同樣htm
0 1 2 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | timestamp delta | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
省略了更多字段, 表示這些省略的字段與上一個chunk同樣.
type3徹底沒有這個header了
若是Message Header中的timestamp或timestamp delta的值爲0xFFFFFF(由於3個字節可能不夠存), 這個字段只才存在
Extended Timestamp存放完整的時間戳
若是Message Header爲TYPE3類型, 若是上一個chunk有Extended Timestamp, 那麼本次的chunk也有Extended Timestamp.
不一樣類型的消息, 消息體各不相同
使用message type id來區分不一樣的協議控制消息, 取值爲1, 2, 3, 5, 6, message stream id必須爲0, chunk stream id必須爲2
4個字節, 大端格式. 設置chunk的最大大小(是指有效載荷的大小, 不包含Header)
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| chunk size (31 bits) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4字節, 大端格式, 通知對方丟棄不完整的數據包.
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | chunk stream id (32 bits) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4字節, 大端格式, 接收者每收到window size大小的數據, 就回復一個Acknowledgement
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | sequence number (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
4字節, 設置window size; 見TYPE ID 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgement Window size (4 bytes) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
設置對方的帶寬輸出大小爲Acknowledgement Window size
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Acknowledgement Window size | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Limit Type | +-+-+-+-+-+-+-+-+
這個用於發送用戶控制消息, message stream id必須爲0, chunk stream id必須爲2
+------------------------------+------------------------- | Event Type (16 bits) | Event Data (變長) +------------------------------+-------------------------
消息類型有
Event | Description |
---|---|
Stream Begin (0) | 服務器發給客戶端, 說明流已經可使用了; 消息體爲4字節的message stream id |
Stream EOF (1) | 服務器發給客戶端, 流已經結束; 消息體爲4字節的message stream id |
StreamDry (2) | 服務器發給客戶端, 沒有數據了; 消息體爲4字節的message stream id |
SetBuffer (3) | 設置服務器的緩衝時間(毫秒), 消息體爲4字節的message stream id + 4字節的大小 |
StreamIs Recorded (4) | 服務器發送給客戶端, 代表服務器會錄製這個流, 消息體爲4字節的message stream id |
PingRequest (6) | ping-pong測試, 服務器發給客戶端, 消息體爲4字節的時間戳 |
PingResponse (7) | ping-pong測試, 客戶端回給服務器, 消息體爲ping消息中的時間戳 |
20表示AMF0格式的命令消息, 17表示AMF3格式的命令消息, 包括connect, createStream, publish, play, pause 如下數據是抓包得出來的
chunk stream id爲3, message stream id爲0 Transaction ID爲固定值1 若是操做成功, 服務器返回_result
, 若是失敗, 則返回_error
chunk stream id爲3, message stream id爲0
Transaction ID自定義, 能夠直接設置爲2, 與connect的transaction id區分開
若是操做成功, 服務器返回_result
, 若是失敗, 則返回_error
chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream_Publish_Start);
chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream.Play.Start)
chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream.Pause.Notify)消息
18爲AMF0格式, 15爲AMF3格式
消息體是音頻數據
chunk stream id爲6, message stream id爲1 chunk stream id能夠隨便設置
消息體是視頻數據
chunk stream id爲5, message stream id爲1 chunk stream id能夠隨便設置
C0爲固定值0x03, C1爲1536個字值
Source Destination Protocol Length Info 192.168.3.212 114.*.*.* RTMP 1591 Handshake C0+C1 //1591-(以太網首部14 + IP首部20 + TCP首部20) = 1537
S0(固定值0x03), S1(1536個字節), S2(1536個字節)
其中S2中的隨機值必須與C1中的隨機值相同
Source Destination Protocol Length Info 114.*.*.* 192.168.3.212 TCP 1514 1935 → 51691 [ACK] Seq=1 Ack=1538 Win=32128 Len=1460 114.*.*.* 192.168.3.212 TCP 1514 1935 → 51691 [ACK] Seq=1461 Ack=1538 Win=32128 Len=1460 114.*.*.* 192.168.3.212 RTMP 207 Handshake S0+S1+S2 //S0+S1+S2數據比較長, 按MTU大小拆分紅多個TCP數據包
C2中的隨機值必須與S1中的隨機值相同
Source Destination Protocol Length Info 192.168.3.212 114.*.*.* RTMP 1590 Handshake C2
Source Destination Protocol Length Info 192.168.3.212 114.*.*.* RTMP 336 connect('mylive')
二進制內容爲
03 //Chunk Basic Header, Stream ID爲3, Message Header類型爲0 (下面有圖) 00 00 00 //3個字節的timestamp 00 01 0c //3個字節的message length, 本例中大小爲268, 不包含header(不包含下面的type id和stream id) 14 //message type id, 下文有說明. 此處值爲20, 表示AMF0格式的命令消息 00 00 00 00 //message stream id, 客戶端能夠填任意值 //如下的內部就是message的body. 須要瞭解AMF0的協議, 才能讀懂 02 00 07 63 6f 6e 6e 65 63 74 //7個字符的字符串, 即'connect', 下面的內容都是connect命令的參數,官方文檔都有說明 00 3f f0 00 00 00 00 00 00 //IEEE754數字 1, Transaction ID 03 //object對象 00 03 61 70 70 //key爲,"app", 02 00 06 6d 79 6c 69 76 65, //value爲字符串"mylive" 00 0e 6f 62 6a 65 63 74 45 6e 63 6f 64 69 6e 67 //key爲"objectEncoding", 使用AMF0仍是AMF3 00 00 00 00 00 00 00 00 00 //數字0, 表示使用AMF0 00 04 66 70 61 64 01 00 00 //如下的類型都是這樣的格式 08 66 6c 61 73 68 56 65 72 02 00 10 57 49 4e 20 31 31 2c 32 2c 32 30 32 2c 32 33 35 00 0b 61 75 64 69 6f 43 6f 64 65 63 73 00 40 90 00 00 00 00 00 00 00 0d 76 69 64 65 6f 46 75 6e 63 74 69 6f 6e 00 3f f0 00 00 00 00 00 00 00 07 70 61 67 65 55 72 6c 05 00 04 70 61 74 68 02 00 06 6d 79 6c 69 76 65 00 0c 63 61 70 61 62 69 6c 69 74 69 65 73 00 40 2e 00 00 00 00 00 00 00 06 73 77 66 55 72 6c 05 00 0b 76 69 64 65 6f 43 6f 64 65 63 73 00 40 60 00 00 00 00 00 00 00 05 74 63 55 72 6c ...
c->s : c0+c1 s->c : s0+s1+s2 c->s : c2 c->s : connect('mylive') s->c : set window size s->c : set bandwidth s->c : connect success c->s : createStream s->c : _result c->s : set buffer length s->c : _result c->s : play s->c : _set chunk size