1. 簡介html
RTMP是Real Time Messaging Protocol(實時消息傳輸協議),此協議基於TCP協議,是一個協議族,包括RTMP基本協議及RTMPT/RTMPS/RTMPE等多種變種。安全
在RTMP協議中信令和媒體數據都稱之爲Message,在網絡中傳輸這些Message,爲了區分它們確定是要加一個Message head的,因此RTMP協議也有一個Message head;由於RTMP協議是基於TCP的,因爲TCP的包長度是有限制的(通常來講不超過1500個字節),而RTMP的Message長度提升喲可能很大,像一個視頻幀的包可能會有幾十甚至幾千K,這個問題就必然有一個分片的問題,在RTMP協議中對應的說法就是chunk,每個Message + head都是由一個和多個chunk組成的。服務器
2. RTMP協議就像一個用來裝數據包的容器,這些數據既能夠是AMF格式的數據,也能夠是FLV中的視/音頻數據。.net
網絡鏈接(Connection)
一個Actionscript鏈接並播放一個流的簡單代碼:
var videoInstance:Video = your_video_instance;
var nc:NetConnection = new NetConnection();
var connected:Boolean = nc.connect("rtmp:/localhost/myapp");
var ns:NetStream = new NetStream(nc);
videoInstance.attachVideo(ns);
ns.play("flvName");
默認端口爲1935
3. 握手請求及應答
Client → Server :向服務器發出握手請求.這不屬於協議包一部分,該握手請求第一個字節爲(0×03),其後跟着1536個字節.儘管看上去這部分的內容對於RTMP協議來講並非相當重要的,但也不可隨意對待.
Server → Client :服務器向客戶端迴應握手請求.這部分的數據仍然不屬於RTMP協議的部分.該回應的起始字節仍然爲(0x03),可是後邊跟着兩個長度爲1536個字節(一共爲3072字節 )的包塊.第一個1536塊看上去彷佛能夠是任意內容,甚至好像能夠是Null都沒有關係.第二個1536的代碼塊,是上一步客戶端向服務器端發送的握手請求的內容.
Client→Server:把上一步服務器向客戶端迴應的第二塊1536個字節的數據塊。
至此客戶端與服務器端的握手結束,下面將發送RTMP協議的包內容.
Client → Server :向服務器發送鏈接包.
Server → Client :服務器迴應.
。。。。。。。
其實RTMP包結構就是使用了AMF格式.
下面是一個關於客戶端向服務器端發送流的流程:
Client→Server :發送一個建立流的請求.
Server→Client :返回一個表示流的索引號.
Client→Server :開始發送.
Client→Server :發送視音頻數據包(這些包在同一個頻道(channel)並用流的索引號來惟一標識).
3.1 RTMP協議封包
RTMP協議封包 由一個包頭和一個包體組成,包頭能夠是4種長度的任意一種:12, 8, 4, 1 byte(s)。完整的RTMP包頭應該是12bytes,包含了時間戳,AMFSize,AMFType,StreamID信息,8字節的包頭只紀錄了時間戳,AMFSize,AMFType,其餘字節的包頭紀錄信息依次類推 。包體最大長度默認爲128字節,經過chunkSize可改變包體最大長度,一般當一段AFM數據超過128字節後,超過128的部分就放到了其餘的RTMP封包中,包頭爲一個字節.
完整的12字節RTMP包頭每一個字節的含義:
用途 |
大小(Byte) |
含義 |
Head_Type |
1 |
包頭 |
TIMER |
3 |
時間戳 |
AMFSize |
3 |
數據大小 |
AMFType |
1 |
數據類型 |
StreamID |
4 |
1流ID |
(1)第一個字節Head_Type的前兩個Bit決定了包頭的長度.它能夠用掩碼0xC0進行"與"計算:
Head_Type的前兩個Bit和長度對應關係:
Bits |
Header Length |
00 |
12 bytes |
01 |
8 bytes |
10 |
4 bytes |
11 |
1 byte |
Head_Type的後面6個Bit和StreamID決定了ChannelID。 StreamID和ChannelID對應關係:StreamID=(ChannelID-4)/5+1
ChannelID |
Use |
02 |
Ping 和ByteRead通道 |
03 |
Invoke通道 咱們的connect() publish()和自字寫的NetConnection.Call() 數據都是在這個通道的 |
04 |
Audio和Vidio通道 |
05 06 07 |
服務器保留,經觀察FMS2用這些Channel也用來發送音頻或視頻數據 |
例如在rtmp包裏面常常看到的0xC2, 就表示一字節的包頭,channel=2.
(2)TIMMER
TiMMER佔3個字節紀錄的是時間戳,音視頻流的時間戳是統一排的。可分爲絕對時間戳和相對時間戳。
fms對於同一個流,發佈的時間戳接受的時間戳是有區別的
publish時間戳,採用相對時間戳,時間戳值等於當前媒體包的絕對時間戳與上個媒體包的絕對時間戳之間的差距,也就是說音視頻時間戳在一個時間軸上面.單位毫秒。
play時間戳,相對時間戳,時間戳值等於當前媒體包的絕對時間戳與上個同類型媒體包的絕對時間戳之間的差距, 也就是說音視頻時間戳分別爲單獨的時間軸,單位毫秒。
flv格式文件時間戳,絕對時間戳,時間戳長度3個字節。超過0xFFFFFF後時間戳值等於TimeStamp & 0xFFFFFF。
flv格式文件影片總時間長度保存在onMetaData的duration屬性裏面,長度爲8個字節,是一個翻轉的double類型。
(3)AMFSize
AMFSize佔三個字節,這個長度是AMF長度,可超過RTMP包的最大長度128字節。若是超過了128字節,那麼由多個後續RTMP封包組合,每一個後續RTMP封包的頭只佔一個字節。通常就是以0xC?開頭。
(4)AMFType
AMFSize佔三個字節,這個長度是AMF長度,可超過RTMP包的最大長度128字節。
AMFType是包的類型視頻
0×01 |
Chunk Size |
changes the chunk size for packets |
0×02 |
Unknown |
|
0×03 |
Bytes Read |
send every x bytes read by both sides |
0×04 |
Ping |
ping is a stream control message, has subtypes |
0×05 |
Server BW |
the servers downstream bw |
0×06 |
Client BW |
the clients upstream bw |
0×07 |
Unknown |
|
0×08 |
Audio Data |
packet containing audio |
0×09 |
Video Data |
packet containing video data |
0x0A-0x0E |
Unknown |
|
0x0F |
FLEX_STREAM_SEND |
TYPE_FLEX_STREAM_SEND |
0x10 |
FLEX_SHARED_OBJECT |
TYPE_FLEX_SHARED_OBJECT |
0x11 |
FLEX_MESSAGE |
TYPE_FLEX_MESSAGE |
0×12 |
Notify |
an invoke which does not expect a reply |
0×13 |
Shared Object |
has subtypes |
0×14 |
Invoke |
like remoting call, used for stream actions too. |
0×16 |
StreamData |
這是FMS3出來後新增的數據類型,這種類型數據中包含AudioData和VideoData |
(5)StreamID
StreamID是音視頻流的ID,若是AMFType!=0x08 或!=0x09那麼 StreamID爲0。
ChannelID 和StreamID之間的計算公式:StreamID=(ChannelID-4)/5+1
例如當ChannelID爲二、三、4時StreamID都爲1 當ChannelID爲9的時候StreamID爲2
參考:http://blog.sina.com.cn/s/blog_4ae178ba0100wis6.html
rtmp_specification_1.0.pdf: