RTMP協議

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

各類ID

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

Basic Header

有三種格式, 本文只說明最簡單的格式 , 另個兩個格式不經常使用. 讀者本身去看文檔翻譯

//一個字節的模式, 存放較小的stream id. (一般stream id都是從3開始的, 一個字節夠了)
 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|fmt| chunk stream id  
+-+-+-+-+-+-+-+-+

fmt用於代表Message Header的格式, 分別爲Type0, Type1, Type2, Type3code

Message Header

根據fmt的的值, 來決定哪一種類型視頻

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                                     |message length |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | message length (cont)         |message type id| msg stream id |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | message stream id (4B)   (小端)               |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
               Chunk Message Header - Type 0

Message Header Type 1 的格式

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

Message Header Type 2 的格式

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同樣.

Message Header Type 3 的格式

type3徹底沒有這個header了

Extended Timestamp

若是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

TYPE ID 1 (Set Chunk Size)

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

TYPE ID 2 (Abort Message)

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

TYPE ID 3 (Acknowledgement)

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

TYPE ID 5 (Window Acknowledgement Size)

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

TYPE ID 6 (Set Peer Bandwidth)

設置對方的帶寬輸出大小爲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    |
+-+-+-+-+-+-+-+-+

TYPE ID 4 (用戶控制消息)

這個用於發送用戶控制消息, 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消息中的時間戳

TYPE ID 20 17 (命令消息)

20表示AMF0格式的命令消息, 17表示AMF3格式的命令消息, 包括connect, createStream, publish, play, pause 如下數據是抓包得出來的

connect

chunk stream id爲3, message stream id爲0 Transaction ID爲固定值1 若是操做成功, 服務器返回_result, 若是失敗, 則返回_error

createStream

chunk stream id爲3, message stream id爲0
Transaction ID自定義, 能夠直接設置爲2, 與connect的transaction id區分開
若是操做成功, 服務器返回_result, 若是失敗, 則返回_error

publish

chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream_Publish_Start);

play

chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream.Play.Start)

pause

chunk stream id爲4, message stream id爲1
Transaction ID爲固定值0 (無心義)
服務器返回onStatus(NetStream.Pause.Notify)消息

TYPE ID 18 15 (用戶自定義消息)

18爲AMF0格式, 15爲AMF3格式

TYPE ID 8 (音頻消息)

消息體是音頻數據
chunk stream id爲6, message stream id爲1 chunk stream id能夠隨便設置

TYPE ID 9 (視頻消息)

消息體是視頻數據
chunk stream id爲5, message stream id爲1 chunk stream id能夠隨便設置

推流過程抓包

握手

終端發送C0,C1給服務器

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

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

C2中的隨機值必須與S1中的隨機值相同

Source          Destination      Protocol   Length  Info
192.168.3.212    114.*.*.*        RTMP       1590    Handshake C2

終端發送connect命令

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

相關文章
相關標籤/搜索