音視頻文章匯總,本文介紹RTMP望薄。
1.本地部署SRS
1.1安裝srs流媒體服務(wù)器
srs官??https://github.com/ossrs/srs
碼云的源速度快?https://gitee.com/winlinvip/srs.oschina.git
github的源速度慢?https://github.com/ossrs/srs.git
選擇版本release3.0
第一步摩泪,獲取SRS肋联。詳細參考GIT獲取代碼
git clone https://gitee.com/winlinvip/srs.oschina.git
cd srs.oschina
#使?當(dāng)前最新的3.0版本
git checkout -b 3.0 remotes/origin/3.0release
cd trunk
第二步宪卿,編譯SRS畜埋。詳細參考Build
./configure && make
第三步缆瓣,編寫SRS配置?件。詳細參考RTMP分發(fā)
將以下內(nèi)容保存為?件,譬如conf/rtmp.conf,服務(wù)器啟動時指定該配置?件(srs的conf?件夾有該?件)纱新。
# conf/rtmp.conf
listen 1935;
max_connections 1000;
vhost __defaultVhost__ {
}
第四步,啟動SRS展氓。詳細參考RTMP分發(fā)
./objs/srs -c conf/rtmp.conf
部署在虛擬機或云服務(wù)器上均可穆趴,使用ffmpeg或OBC客戶端推流脸爱,ffplay或VLC拉流進行播放
2.RTMP原理
Real Time Messaging Protocol) 是一個應(yīng)用層協(xié)??主要用于在Flash player和服務(wù)器之間傳輸視頻,音頻未妹,控制命令等內(nèi)容簿废。協(xié)議的突出優(yōu)點是:低延時。
FFMPEG
推流 +FFPLAY 播放
推流
ffmpeg -re -i /mnt/hgfs/linux/vod/35.mp4 -c copy -f flv rtmp://192.168.100.41/live/35
拉流
ffplay rtmp://192.168.100.41/live/35
FFPLAY
播放
拉流
ffplay rtmp://202.69.69.180:443/webcast/bshdlive-pc
2.1RTMP播放流程
2.2推流流程
RTMP是基于TCP的應(yīng)用層協(xié)議络它。TCP的三次握手可實現(xiàn)RTMP 客戶端與RTMP服務(wù)器的指定端口(默認(rèn)端口為1935)建立一個可靠的網(wǎng)絡(luò)連接族檬。這里的的網(wǎng)絡(luò)連接接才是真正的物理連接。
完成了三次握手,客戶端和服務(wù)器端就可以開始傳輸數(shù)據(jù)化戳。
2.2.1TCP三次握手修高速公路
經(jīng)過三次握手客戶端與服務(wù)器端1935端口建立了TCP Connection
2.2.2RTMP握手
與其叫RTMP握手其實實質(zhì)上起到的是的作用单料。RTMP握手的基本流程
RTMP握手主要分為簡單握手和復(fù)雜握手。
簡單握手
簡單握手中C1 和 S1 從第9個字節(jié)開始都是隨機數(shù)点楼。
S2 是 C1 的復(fù)制扫尖。C2 是 S1 的復(fù)制。
協(xié)議版本號?8bit
C0客戶端版本
S服務(wù)器版本
目前版本為3(0 1 2已經(jīng)廢棄)
C1和S1數(shù)據(jù)包的長度都是1536字節(jié)
03( 00 (C1 開始 00 00 00 09 00 7c 02 f7 78 55 1e ce ab 8e)
S1 片段 00 90 65 30 0d 0e 0a 0d 64 84 1c ad 1e 7f 0c
C2和S2數(shù)據(jù)包長度都是1536字節(jié)掠廓,基本就是S1和C1的副本换怖。 ??
S2片段
復(fù)雜握手
相對于簡單握手和復(fù)雜握手主要是增加了更嚴(yán)格的驗證。
主要是將簡單握手中的1528Bytes隨機數(shù)的部分平均分成兩部分,一部分764Bytes存儲,public key(公共密鑰)蟀瞧,另一部分764Bytes存儲digest(密文,32字節(jié))沉颂。
另外復(fù)雜握手有一個明顯的特征就是:Version部分不為0
服務(wù)器端可根據(jù)這個來判斷是否簡單握手或復(fù)雜握手。
2.2.3Connect連接
這里也叫連接悦污,連接的是什么呢铸屉?必須明白RTMP中一個很重要的概念A(yù)pplication Instance。
不同的Application Instance 可根據(jù)功能等進行區(qū)分,比如直播可以用live來表示,點播回放可以用vod來表示切端。
rtmp://192.168.100.41/live/36
其中l(wèi)ive就是Application(Instance sport), music播放該流時connect 的地址就是
rtmp://192.168.100.41/live/36
2.2.4createStream(創(chuàng)建流)-創(chuàng)建邏輯通道
createStream命令用于創(chuàng)建邏輯通道彻坛,邏輯通道用于傳輸視頻、音頻、metadata小压。
在服務(wù)器的響應(yīng)報文中會返回Stream ID,用于唯一的標(biāo)示該Stream线梗。注意Message ID和Stream ID的區(qū)別。
The command structure from the client to the server is as follows:
The command structure from server to client is as follows:
2.2.5play(播放)
客戶端發(fā)送play命令來播放指定流怠益。開始傳輸數(shù)據(jù)仪搔。
如果發(fā)送play命令后想立即播放,需要清空play隊列中的其它流蜻牢,并將reset置為true烤咧。
2.2.6delete刪除流
The command structure from the client to the server is as follows:
刪除指定Stream ID 的流。服務(wù)器 不用對?條命令發(fā)?響應(yīng)報文抢呆。
2.3RTMP層次
RTMP層次(數(shù)據(jù)發(fā)送角度)
RTMP層次(數(shù)據(jù)接收角度)
RTMP層次(協(xié)議角度)
2.3.1Message和Chunk
Message RTMP 中一個重要的概念就是消息煮嫌。
2.3.2消息分類
消息主要分為三類:協(xié)議控制消息、數(shù)據(jù)消息抱虐、命令消息 等昌阿。
協(xié)議控制消息Message Type ID = 1 2 3 5 6 和 Message Type ID = 4 兩大類主要用于協(xié)議內(nèi)的控制消息,此部分后續(xù)將詳細分析恳邀。
數(shù)據(jù)消息
Message Type ID = 8 9 18
8: Audio ??數(shù)據(jù)
9: Video ??數(shù)據(jù)
18: Metadata 包括音視頻編碼懦冰、視頻寬高等信息。
命令消息
Command Message (20, 17)
此類型消息主?有 NetConnection 和 NetStream 兩個類谣沸,兩個類分別有多個函數(shù)刷钢,該消息的調(diào)用,可理解為遠程函數(shù)調(diào)用乳附。
stream ID
Message StreamID是音視頻流的唯一ID, 一路流如果既有音頻包又有視頻包内地,那么音頻包的StreamID和他視頻包的StreamID相同。
Chunk網(wǎng)絡(luò)中實際發(fā)送的內(nèi)容赋除。
message chunk
cs id即是 Chunk Stream ID
Chunk Stream ID
Each chunk that is created has a unique ID associated with it called chunk stream ID阱缓。(5.3.Chunking);
因為一個流當(dāng)中可以交錯傳輸多種消息類型的Chunk ??
那么多個Chunk怎么標(biāo)記同屬于同一類Message的呢?
答案是:Chunk Stream ID 區(qū)分的同一個Chunk Stream ID必然屬于同一個Message。
RTMP流中視頻和音頻擁有單獨的Chunk Stream ID贤重,比如音頻的cs id=20茬祷,視頻的cs id=21 。接收端接收到Chunk之后根據(jù)cs id分別將音頻和視頻拼成消息并蝗。
Message & Chunk
Message切割成一個或多個Chunk,然后在網(wǎng)絡(luò)上進行發(fā)送祭犯。當(dāng)發(fā)送時,一個chunk發(fā)送完畢后才可以發(fā)送下一個
chunk滚停。
拆分的時候的Chunk Size是128字節(jié)沃粗,以Message大小為300字節(jié)舉例進行拆分。300 = 128 + 128 + 44
發(fā)送端
首先將數(shù)據(jù)加工成消息(中間物),然后再將消息分割成Chunk(加上Chunk Header)键畴,然后將Chunk通過網(wǎng)絡(luò)發(fā)送出去最盅。
接收端
接收端將接收到的Chunk組裝成消息突雪。
RTMP協(xié)議角度
RTMP Chunk Header
RTMP Chunk Header的長度不是固定的,分為12 Bytes、8 Bytes涡贱、4 Bytes咏删、1 Byte四種,?由RTMP Chunk Header前2位決定。
一場直播如果不中斷的話问词,是不是只有一個流督函,也就是Message Stream ID一直到直播結(jié)束都是唯一的,Message 里面的Message Stream Id和Chunk里面的Chunk Stream Id屬于兩個不同的東西激挪,因為Chunk Stream Id用來區(qū)分音頻和視頻流
為什么Chunk Header會存在不同的長度
一般情況下msg stream id是不會變的辰狡,所以針對視頻或音頻,除了第一個RTMP Chunk Header是 12Byte的,后續(xù)即可采用8Bytes的垄分。 因為msg stream id占4個Bytes可省去宛篇。
如果消息的長度(message length)和類型(msg type id, 如視頻為9或音頻為8)又相同,即可將這兩部分也省去,RTMP Chunk Header采用4Bytes類型的薄湿。
如果當(dāng)前Chunk與之前的Chunk相比, msg stream id 相同,msg type id相同,message length相同,而且?都屬于同一個消息叫倍,由同一個Message切割成),這類Chunk的時間戳(timestamp)也是相同的,故后續(xù)的也可以省去,RTMP Chunk Header采用1 Byte類型的嘿般。
當(dāng)Chunk Size足夠大時(一般不這么干),此時所有的 Message都只能相應(yīng)切割成一個Chunk,該Chunk僅msg stream id相同段标。此時基本上除了第一個Chunk的Header是12Bytes外涯冠,其它所有Chunk的Header是8Bytes炉奴。
12Bytes Chunk Header舉例
RTMP Header(12 Bytes)
一般只有rtmp流剛開始的metadata、絕對時間戳的視頻或音頻是12Bytes蛇更。
有些控制消息也是12Bytes,比如connect瞻赶。
8Bytes Chunk Header舉例
4Bytes Chunk Header舉例
1Bytes Chunk Header舉例
RTMP傳輸基本流程
發(fā)送端
Step 1:
把數(shù)據(jù)封裝成消息(Message)。
Step 2:
把消息分割成消息塊(Chunk, 網(wǎng)絡(luò)中實際傳輸?shù)膬?nèi)容)派任。
Step 3:
將分割后的消息塊(Chunk)砸逊,通過TCP協(xié)議發(fā)出去。
接收端
Step 1:
在TCP協(xié)議收到數(shù)據(jù)后,先將消息塊重新組合成消息(Message)掌逛。
Step 2:
通過對消息進行解封裝處理就可以恢復(fù)出數(shù)據(jù)师逸。
RTMP為什么要將Message劃分為Chunk?
在互聯(lián)網(wǎng)中傳輸數(shù)據(jù)時,消息(Message)會被拆分成更小的單元,稱為消息塊(Chunk)豆混。
大的Message被切割成利于網(wǎng)絡(luò)上傳輸?shù)男hunk,切成小塊篓像,可防止大的數(shù)據(jù)塊(如視頻數(shù)據(jù))阻塞小的數(shù)據(jù)塊(如音頻數(shù)據(jù)或控制信號)。
如果一幀1080P I幀數(shù)據(jù)量為244KBytes,假設(shè)帶寬為10Mbit/s,傳輸一幀的耗時為:2441024 8/(1010241024) = 0.190625秒 =190毫秒
假如要實時傳輸25幀的I幀文件皿伺,即允許每幀傳輸最大耗時為40毫秒员辩,需要帶寬47.65625Mbit,這還沒包括傳輸中的ACK數(shù)據(jù)。
在RTMP中鸵鸥,消息(Message)主要分為兩大類:控制消息和數(shù)據(jù)消息奠滑。數(shù)據(jù)消息中由包括Video消息和Audio消息等。
消息都是怎么進行管理的?
通路只有一條(RTMP是單通路),到底誰先走呢宋税,誰后走呢摊崭?
答案是:分優(yōu)先級,優(yōu)先級高的先行杰赛。優(yōu)先級低的不能阻塞優(yōu)先級高的爽室。
RTMP Chunk Stream層級沒有優(yōu)先級的劃分,是在高層次Message stream提供優(yōu)先級的劃分。
不同類型的消息會被分配不同的優(yōu)先級淆攻,當(dāng)網(wǎng)絡(luò)傳輸能力受限時阔墩,優(yōu)先級用來控制消息在網(wǎng)絡(luò)底層的排隊順序。
比如當(dāng)客戶端網(wǎng)絡(luò)不佳時瓶珊,流媒體服務(wù)器可能會選擇丟棄視頻信息啸箫,以保證音頻消息可以及時送達客戶端。
RTMP Chunk Stream層級允許在Message stream層次伞芹,將大消息切割成小消息忘苛,這樣可以避免大的低優(yōu)先級的消息(如視頻消息)阻塞小的高優(yōu)先級的消息(如音頻消息或控制消息)。
RTMP消息優(yōu)先等級
Protocol Control Messages屬于RTMP Chunk Stream層級的控制消息唱较,用于該協(xié)議的內(nèi)部控制扎唾。
User Control Message 是RTMP streaming layer(即Message stream層次)的消息。
協(xié)議先行
協(xié)議控制消息 Protocol Control Messages 和用戶控制消息User Control Messages 應(yīng)該包含消息流 ID 0(控制流)和塊流ID 2,并且有最高的發(fā)送優(yōu)先級南缓。
數(shù)據(jù)次之
數(shù)據(jù)消息(視頻信息胸遇、音頻消息)比控制信息的優(yōu)先級低。另外,一般情況下,音頻消息比視頻數(shù)優(yōu)先級高汉形。
2.4RTMP協(xié)議-時間戳
基本介紹
- RTMP中時間戳的單位為毫秒(ms)
- 時間戳為相對于某個時間點的相對值
- 時間戳的長度為32bit
Timestamp: Four-byte field that contains a timestamp of the message.
The 4 bytes are packed in the big endian order.
?RTMP Message的時間戳4個字節(jié)
?大端存儲
Chunk時間戳
Chunk Format
用wireshark轉(zhuǎn)包分析發(fā)現(xiàn),rtmp流的chunk視頻流 或(音頻流)除第一個視頻時間戳為絕對時間戳外,后續(xù)的時間戳均為timestamp delta,即當(dāng)前時間戳與上一個時間戳的差值澎羞。
比如幀率為25幀每秒的視頻流,timestamp delta基本上都為40ms涌穆。
通常情況下Chunk的時間戳(包括絕對時間戳和 Timestamp delta)是3個字節(jié)仇箱。
但時間戳值超過0xFFFFFF時,啟用Extended Timestamp(4個字節(jié)來表示時間戳)
通常情況下-----3字節(jié)
三字節(jié)的timestamp可能為絕對timestamp或timestamp delta蚌讼。
timestamp delta (3 bytes): For a type 1 or type 2 chunk, the difference between the previous chunk’s timestamp and the current chunk’s timestamp is sent here.
If the delta is greater than or equal to 16777215 (hexadecimal 0xFFFFFF), this field MUST be 16777215, indicating the
presence of the Extended Timestamp field to encode the full 32 bit delta.
Otherwise, this field SHOULD be the actual delta.
timestamp delta的值超過16777215(即16進制的 0xFFFFFF)時,這時候這三個字節(jié)必須置為0xFFFFFF以此來標(biāo)示Extended Timestamp(4字節(jié))將會存在,?由Extended Timestamp來表示時間戳。