基本概念:
RTMP協(xié)議規(guī)定,播放一個(gè)流媒體有兩個(gè)前提步驟:
第一步,建立一個(gè)網(wǎng)絡(luò)連接(NetConnection)唤蔗。
第二步义锥,建立一個(gè)網(wǎng)絡(luò)流(NetStream)柳沙。
網(wǎng)絡(luò)連接代表服務(wù)器端應(yīng)用程序和客戶端之間基礎(chǔ)的連通關(guān)系,網(wǎng)絡(luò)流代表了發(fā)送多媒體數(shù)據(jù)的通道拌倍。服務(wù)器和客戶端之間只能建立一個(gè)網(wǎng)絡(luò)連接赂鲤,但是基于該連接可以創(chuàng)建很多網(wǎng)絡(luò)流。
播放一個(gè)RTMP協(xié)議的流媒體需要經(jīng)過(guò)四個(gè)階段:
- 握手階段
- 建立連接階段
- 建立流階段
- 播放階段
RTMP連接都是以握手作為開(kāi)始的柱恤,建立連接階段用于建立客戶端與服務(wù)器之間的“網(wǎng)絡(luò)連接”数初。
建立流階段用于建立客戶端與服務(wù)器之間的“網(wǎng)絡(luò)流”。
播放階段用于傳輸視音頻數(shù)據(jù)膨更。
下面是使用librtmp執(zhí)行拉流過(guò)程的API調(diào)用流妙真,如下:
抓包分析:
RTMP定義了較為完善的協(xié)議標(biāo)準(zhǔn),但是每種播放工具的實(shí)現(xiàn)略有差異荚守,下面是我使用VLC播放器拉流時(shí)抓取的報(bào)文珍德,使用wireshark分析過(guò)程整理為下面的圖文。
先看一張總覽圖矗漾,圖中顯示的報(bào)文和時(shí)序包含了握手锈候、建立連接、建立流和播放階段敞贡,如下:
還有申明下泵琳,以下的流程是根據(jù)實(shí)際抓包情況分析出來(lái)的,由于不同的工具省略了一些不必要的步驟,故不代表標(biāo)準(zhǔn)結(jié)果获列,僅供參考谷市。
握手階段:
由于講解握手過(guò)程的文檔資料比較多,我這里就不重復(fù)描述了击孩,摘圖如下:
個(gè)人認(rèn)為這張圖是最符合標(biāo)準(zhǔn)時(shí)序的迫悠,細(xì)節(jié)拿捏得非常講究,雖然很多實(shí)現(xiàn)簡(jiǎn)化了流程巩梢。
建立連接階段:
包括以下報(bào)文和步驟:
- 客戶端發(fā)起連接請(qǐng)求
- 服務(wù)器設(shè)置客戶端的應(yīng)答窗口大小
- 服務(wù)器設(shè)置客戶端的發(fā)送帶寬大小
- 服務(wù)器設(shè)置客戶端的接收塊大小
- 服務(wù)器響應(yīng)連接結(jié)果
- 客戶端設(shè)置服務(wù)器的應(yīng)答窗口大小
客戶端發(fā)起連接請(qǐng)求:
協(xié)議截圖如下:
協(xié)議方向:客戶端 -> 服務(wù)器
塊頭字段:
???? HeaderType: 0
???? CSID: 3
???? 時(shí)間戳:0
???? BodySize: 201
???? TypeID: 0x14
???? Stream ID: 0
負(fù)載格式:AMF0表示创泄,connect 1 object1
???? object1屬性列表:
???? ???? "app": "live"
???? ???? "flashVer": "LNX 9,0,124,2"
???? ???? "tcUrl": "rtmp://127.0.0.1:1935/live"
???? ???? "fpad": false
???? ???? "capabilities": 15,
???? ???? "audioCodes": 4071,
???? ???? "videoCodes": 252,
???? ???? "videoFunction": 1,
???? ???? End Of Object Marker
服務(wù)器設(shè)置客戶端的應(yīng)答窗口大小:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 2
???? 時(shí)間戳:0
???? BodySize: 4
???? TypeID: 0x05
???? Stream ID: 0
負(fù)載格式:4字節(jié)整型表示括蝠,如5000000
服務(wù)器設(shè)置客戶端的發(fā)送帶寬大芯弦帧:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 2
???? 時(shí)間戳:0
???? BodySize: 5
???? TypeID: 0x06
???? Stream ID: 0
負(fù)載格式:5字節(jié)整型表示,前4字節(jié)為帶寬忌警,后1字節(jié)為標(biāo)志搁拙,如5000000, 2(動(dòng)態(tài)調(diào)整)
服務(wù)器設(shè)置客戶端的接收塊大小:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 2
???? 時(shí)間戳:0
???? BodySize: 4
???? TypeID: 0x01
???? Stream ID: 0
負(fù)載格式:4字節(jié)整型表示法绵,如4096
服務(wù)器響應(yīng)連接結(jié)果:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 3
???? 時(shí)間戳:0
???? BodySize: 190
???? TypeID: 0x14
???? Stream ID: 0
負(fù)載格式:AMF0表示感混,_result 1 object1 object2
???? object1屬性列表:
???? ???? "fmsVer": "FMS/3,0,1,123"
???? ???? "capabilities": 31,
???? ???? End Of Object Marker
???? object2屬性列表:
???? ???? "level": "status"
???? ???? "code": "NetConnection.Connect.Success",
???? ???? "description": "Connection succeeded.",
???? ???? "objectEncoding": 0
???? ???? End Of Object Marker
客戶端設(shè)置服務(wù)器的應(yīng)答窗口大小:
協(xié)議截圖如下:
協(xié)議方向:客戶端 -> 服務(wù)器
塊頭字段:
???? HeaderType: 0
???? CSID: 2
???? 時(shí)間戳:0
???? BodySize: 4
???? TypeID: 0x05
???? Stream ID: 0
負(fù)載格式:4字節(jié)整型表示礼烈,如5000000
建立流階段:
包括以下報(bào)文和步驟:
- 客戶端發(fā)起創(chuàng)建流請(qǐng)求
- 服務(wù)器響應(yīng)創(chuàng)建流結(jié)果
客戶端發(fā)起創(chuàng)建流請(qǐng)求:
協(xié)議截圖如下:
協(xié)議方向:客戶端 -> 服務(wù)器
塊頭字段:
???? HeaderType: 1
???? CSID: 3
???? 時(shí)間戳:0
???? BodySize: 25
???? TypeID: 0x14
負(fù)載格式:AMF0表示弧满,createStream 2 object(Null)
服務(wù)器響應(yīng)創(chuàng)建流結(jié)果:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 3
???? 時(shí)間戳:0
???? BodySize: 29
???? TypeID: 0x14
???? Stream ID: 0
負(fù)載格式:AMF0表示,_result 2 object(Null) Number(1)
播放階段:
包括以下報(bào)文和步驟:
- 客戶端發(fā)起播放節(jié)目請(qǐng)求
- 客戶端通知服務(wù)器設(shè)置緩沖區(qū)大小
- 服務(wù)器通知客戶端啟動(dòng)流
- 服務(wù)器通知客戶端流進(jìn)入播放狀態(tài)
- 服務(wù)器向客戶端發(fā)送媒體元數(shù)據(jù)
- 服務(wù)器向客戶端發(fā)送媒體數(shù)據(jù)
客戶端發(fā)起播放節(jié)目請(qǐng)求:
協(xié)議截圖如下:
協(xié)議方向:客戶端 -> 服務(wù)器
塊頭字段:
???? HeaderType: 0
???? CSID: 8
???? 時(shí)間戳:0
???? BodySize: 30
???? TypeID: 0x14
???? Stream ID: 1
負(fù)載格式:AMF0表示此熬,play 4 Object(Null) String節(jié)目ID("a") Number開(kāi)始時(shí)間(-2000)
客戶端通知服務(wù)器設(shè)置緩沖區(qū)大型ノ亍:
協(xié)議截圖如下:
協(xié)議方向:客戶端 -> 服務(wù)器
塊頭字段:
???? HeaderType: 1
???? CSID: 2
???? 時(shí)間戳:1
???? BodySize: 10
???? TypeID: 0x04
負(fù)載格式:Event Type,2字節(jié)的類型(3) 4字節(jié)的流ID(1) 4字節(jié)的MS時(shí)間單位(3000)
服務(wù)器通知客戶端啟動(dòng)流:
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 2
???? 時(shí)間戳:0
???? BodySize: 6
???? TypeID: 0x04
負(fù)載格式:Event Type犀忱,2字節(jié)的類型(0) 4字節(jié)的流ID(1)
服務(wù)器通知客戶端流進(jìn)入播放狀態(tài):
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 5
???? 時(shí)間戳:0
???? BodySize: 96
???? TypeID: 0x14
???? Stream ID: 1
負(fù)載格式:AMF0表示募谎,onStatus 0 Object1(Null) object2
???? object2屬性列表:
???? ???? "level": "status"
???? ???? "code": "NetStream.Play.Start",
???? ???? "description": "Start live",
???? ???? End Of Object Marker
服務(wù)器向客戶端發(fā)送媒體元數(shù)據(jù):
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 5
???? 時(shí)間戳:0
???? BodySize: 387
???? TypeID: 0x12
???? Stream ID: 1
負(fù)載格式:AMF0表示,onMetaData object
???? object屬性列表:
???? ???? "Server": "NGINX RTMP"
???? ???? "width": 480,
???? ???? "height": 270,
???? ???? "displayWidth": 480,
???? ???? "displayHeight": 270,
???? ???? "duration": 0,
???? ???? "framerate": 16,
???? ???? "fps": 16,
???? ???? "videodatarate": 193,
???? ???? "videocodeid": 7,
???? ???? "audiodatarate": 52,
???? ???? "audiocodeid": 10,
???? ???? "profile": "",
???? ???? "level": "",
???? ???? End Of Object Marker
服務(wù)器向客戶端發(fā)送媒體數(shù)據(jù):
協(xié)議截圖如下:
協(xié)議方向:服務(wù)器 -> 客戶端
塊頭字段:
???? HeaderType: 0
???? CSID: 6
???? 時(shí)間戳:0
???? BodySize: 209
???? TypeID: 0x08
???? Stream ID: 1
負(fù)載格式:格式頭阴汇,媒體數(shù)據(jù)
流程時(shí)序:
結(jié)合以上分析数冬,總結(jié)時(shí)序圖如下:
另外,關(guān)于HeaderType和CSID的運(yùn)用搀庶,先歸納使用情況:
0x14(connect) HeaderType: 0 CSID: 3
0x05(Ack Window Size) HeaderType: 0 CSID: 2
0x06(BrandWidth) HeaderType: 0 CSID: 2
0x01(ChunkSize) HeaderType: 0 CSID: 2
0x14(connect _result) HeaderType: 0 CSID: 3
0x14(createStream) HeaderType: 1 CSID: 3
0x14(createStream _result) HeaderType: 0 CSID: 3
0x14(play) HeaderType: 0 CSID: 8
0x04(SetBufferMS) HeaderType: 1 CSID: 2
0x04(Stream Begin) HeaderType: 0 CSID: 2
0x14(play onStatus) HeaderType: 0 CSID: 5
0x12(onMetaData) HeaderType: 0 CSID: 5
0x08(audioData) HeaderType: 0 CSID: 6
0x09(videoData) HeaderType: 0 CSID: 7
總結(jié):
關(guān)于HeaderType的運(yùn)用拐纱,有以下規(guī)則:
createStream使用1號(hào)HeaderType,借用3號(hào)CSID之前的StreamID哥倔。
SetBufferMS使用1號(hào)HeaderType秸架。
audioData和videoData視情況使用0、1咆蒿、2东抹、3號(hào)HeaderType蚂子。
關(guān)于CSID的運(yùn)用,有以下規(guī)則:
- 0x01~0x06命令用2號(hào)CSID缭黔。
- 大部分0x14命令用3號(hào)CSID食茎,但有例外,如play用8號(hào)CSID馏谨,play onStatus用5號(hào)CSID董瞻。
- 0x12媒體元數(shù)據(jù)用5號(hào)CSID。
- 0x08音頻數(shù)據(jù)用6號(hào)CSID田巴。
- 0x09視頻數(shù)據(jù)用7號(hào)CSID。