RTMP 協(xié)議研究
Posted on 2010-01-26 14:14 S.l.e!ep.¢% 閱讀(1923) 評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi): A·M·F·3RTMP 協(xié)議研究
1 協(xié)議研究概述
?? 協(xié)議設(shè)計(jì)和分析一直都是在工作遇到,正好在這里總結(jié)一下,說(shuō)到協(xié)議,在這個(gè)網(wǎng)絡(luò)的時(shí)代,沒(méi)有人可以離開(kāi)它了。他存在我們生活中的任何角落,只不過(guò)我們平時(shí),并沒(méi)有注意到它的存在,可以這么說(shuō)如果沒(méi)有協(xié)議,我們生活和日常的工作生產(chǎn)都不能進(jìn)行。如果仔細(xì)想想你生活中用到的所有東西,協(xié)議已經(jīng)包含其中。那到底什么是協(xié)議呢?說(shuō)的簡(jiǎn)單一點(diǎn)就是雙方達(dá)成的共識(shí),以便更好的交流,理論上協(xié)議是什么呢?如果學(xué)過(guò)《信號(hào)與系統(tǒng)》的人都知道有個(gè)簡(jiǎn)單的道理,就是信息在經(jīng)過(guò)一個(gè)管道的符號(hào)集,到另一個(gè)符號(hào)集時(shí)信息不會(huì)丟失。
??? 任何復(fù)雜的事物都有個(gè)最簡(jiǎn)單的本質(zhì),網(wǎng)絡(luò)上的協(xié)議也是這樣,有個(gè)最基本的本質(zhì)。除去上下層的概念,協(xié)議就只剩下通信雙方實(shí)體的規(guī)則。
?? 一般的協(xié)議都包含最基本的協(xié)議頭,不管是物理層、鏈路層、還是網(wǎng)絡(luò)層,這個(gè)頭就構(gòu)成了協(xié)議的本質(zhì)東西。通常協(xié)議頭要包含以下最基本的三項(xiàng)信息:
雙方實(shí)體的唯一標(biāo)示,用來(lái)標(biāo)示通信雙方的實(shí)體。
類(lèi)型描述或者是凈核描述,標(biāo)志凈核的內(nèi)容。
協(xié)議凈核的長(zhǎng)度,用來(lái)在萃取凈核的內(nèi)容應(yīng)用。
?? 其中,前兩項(xiàng)是必須要有的,沒(méi)有他們,通信雙方的交互根本得不到保證,第三項(xiàng)在不太靈活的通信中可以去掉,而有第二項(xiàng)的類(lèi)型推出。
??? 協(xié)議的豐富性,有凈核的多樣性體現(xiàn)。
?? 協(xié)議頭除了以上的三項(xiàng),還可以增加更多的信息(比如控制信息、時(shí)間信息等),取決于具體的應(yīng)用。找到這些基本的東西,再去看協(xié)議的時(shí)候,能夠更好的抓住協(xié)議的主體進(jìn)行分析和設(shè)計(jì)了。
???????????? 如圖?? 協(xié)議物理結(jié)構(gòu)
2 RTMP 協(xié)議概述
?? RTMP 協(xié)議是被 Flash 用于對(duì)象、視頻、音頻的傳輸。該協(xié)議建立在 TCP 協(xié)議或者輪詢(xún) HTTP 協(xié)議之上, RTMP 協(xié)議就像一個(gè)用來(lái)裝數(shù)據(jù)包的容器,這些數(shù)據(jù)可以是 AMF 格式的數(shù)據(jù),也可以是 FLV 中的視 / 音頻數(shù)據(jù)。一個(gè)單一的連接可以通過(guò)不同的通道傳輸多路網(wǎng)絡(luò)流,這些通道中的包都是按照固定大小的包傳輸?shù)?.
3 RTMP 協(xié)議部分
3.1 協(xié)議頭
struct RTMP_HEAD
{
????????? char cChannelid : 6;// 第一個(gè)字節(jié)的后 6 位
????????? char cCheadsize ; // 第一個(gè)字節(jié)的頭兩位
????? char cTimer[3];? // 三個(gè)字節(jié)表示的時(shí)間信息
????? char cLength[3]; // 三個(gè)字節(jié)表示的長(zhǎng)度
????? char cDatatype; // 數(shù)據(jù)類(lèi)型
????? char sStreamid[4]; // 流標(biāo)識(shí)
};
這里有三個(gè)最基本的元素(唯一標(biāo)示 )、(類(lèi)型 )和(凈核的長(zhǎng)度 )分別是: cChannelid 、 cDatatype 和 cLength 。
3.2 數(shù)據(jù)類(lèi)型
數(shù)據(jù)類(lèi)型 決定了協(xié)議上層可以做的具體的事情,和使用協(xié)議的人必須遵循的規(guī)則。
同時(shí)數(shù)據(jù)類(lèi)型 說(shuō)明了凈核 的基本內(nèi)容。
RTMP 數(shù)據(jù)類(lèi)型:
0×01? Chunk Size? changes the chunk size for packets?
0×02? Unknown? anyone know this one??
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? anyone know this one??
0×08? Audio Data? packet containing audio?
0×09? Video Data? packet containing video data?
0x0A - 0×11? Unknown? anyone know??
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.?
3.3 協(xié)議的凈核
?? RTMP 的協(xié)議凈核是用 AMF 格式來(lái)描述, AMF 格式本身的產(chǎn)生就是為了 RTMP 協(xié)議服務(wù)的,最初的 RTMP 采用 XML 的形式傳輸數(shù)據(jù),但 XML 只是字符形式的值對(duì)的格式傳輸數(shù)據(jù),而隨著應(yīng)用的普及這完全不能滿(mǎn)足要求了,比如對(duì)象、結(jié)構(gòu)、數(shù)組,甚至可以是數(shù)據(jù)集,配合 DataGrid 組件可以很方便地顯示數(shù)據(jù)。
為了處理復(fù)雜數(shù)據(jù)類(lèi)型,采用一種獨(dú)有的方式使 Flash 與應(yīng)用服務(wù)器間可以來(lái)回傳送數(shù)據(jù)勢(shì)在必行。于是 AMF 應(yīng)運(yùn)而生。
AMF 是 Adobe 獨(dú)家開(kāi)發(fā)出來(lái)的通信協(xié)議,它采用二進(jìn)制壓縮,序列化、反序列化、傳輸數(shù)據(jù),從而為 Flash 播放器與 Flash Remoting 網(wǎng)關(guān)通信提供了一種輕量級(jí)的、高效能的通信方式。如下圖所示。
?
AMF 最大的特色在于可直接將 Flash 內(nèi)置對(duì)象,例如 Object, Array, Date, XML ,傳回服務(wù)器端,并且在服務(wù)器端自動(dòng)進(jìn)行解析成適當(dāng)?shù)膶?duì)象,這就減輕了開(kāi)發(fā)人員繁復(fù)工作,同時(shí)也更省了開(kāi)發(fā)時(shí)間。由于 AMF 采用二進(jìn)制編碼,這種方式可以高度壓縮數(shù)據(jù),因此非常適合用 來(lái)傳遞大量的資料。數(shù)據(jù)量越大, Flash Remoting 的傳輸效能就越高,遠(yuǎn)遠(yuǎn)超過(guò) Web Service 。至于 XML, LoadVars 和 loadVariables() ,它們使用純文本的傳輸方式,效能就更不能與 Flash Remoting 相提并論了。
注意: Flash Remoting 需要瀏覽器支持 Binary POST , Flash 播放器在 Netscape 6.x. 環(huán)境下運(yùn)行 Flash Remoting 會(huì)不起作用( Flash Remoting 調(diào)用沒(méi)有效果也不返回錯(cuò)誤), Netscape 7 已經(jīng)糾正了這個(gè) bug 。對(duì)于早期 Safari 和 Chimera 版的蘋(píng)果機(jī)也有這個(gè)問(wèn)題。
同樣是輕量級(jí)數(shù)據(jù)交換協(xié)議,同樣是通過(guò)調(diào)用遠(yuǎn)程服務(wù),同樣是基于標(biāo)準(zhǔn)的 HTTP 和 HTTPS 協(xié)議, Flash Remoting 為什么選擇了使用 AMF 而放棄了 SOAP 與 Flash 播放器通信呢? 有如下原因:
?
SOAP 將數(shù)據(jù)處理成 XML 格式,相對(duì)于二進(jìn)制的 AFM 太冗長(zhǎng)了;?
AMF 能更有效序列化數(shù)據(jù);因?yàn)?AMF 的初衷只是為了支持 Flash ActionScript 的數(shù)據(jù)類(lèi)型,而 SOAP 卻致力于提供更廣泛的用途;?
AMF 支持 Flash 播放器 6 只需要瀏覽器增加 4 KB 左右(壓縮后)的大小,而 SOAP 就大多了;?
SOAP 的一些頭部文件請(qǐng)求在 Flash 播放器 6 不支持。那 Flash 播放器 6 為什么能訪問(wèn)基于 SOAP 的 Web 服務(wù)呢?原來(lái) Flash Remoting 網(wǎng)關(guān)將 SOAP 請(qǐng)求在服務(wù)器端與轉(zhuǎn)換成 AFM 格式,然后利用 AFM 與 Flash 播放器通信。另外, AMF 包中包含 onResult 事件(比如說(shuō) response 事件)和 onStatus 事件(比如說(shuō) error 事件),這些事件對(duì)象在 Flash 中可以直接使用。?
AMF 從 Flash MX 時(shí)代的 AMF0 發(fā)展到現(xiàn)在的 AMF3 。 AMF3 用作 Flash Playe 9 的 ActionScript 3.0 的默認(rèn)序列化格式,而 AMF0 則用作舊版的 ActionScript 1.0 和 2.0 的序列化格式。 在網(wǎng)絡(luò)傳輸數(shù)據(jù)方面, AMF3 比 AMF0 更有效率。 AMF3 能將 int 和 uint 對(duì)象作為整數(shù)( integer )傳輸,并且能序列化 ActionScript 3.0 才支持的數(shù)據(jù)類(lèi)型 , 比如 ByteArray , XML 和 Iexternalizable 。
????? AMF 很好的解決了內(nèi)容的豐富性。(具體 AMF 格式參考附件格式文檔)
3.3.1 AMF中的數(shù)據(jù)類(lèi)型Data Types
AMF0 supports the following data types (with their type field values):
NUMBER = 0x00
BOOLEAN = 0x01
STRING = 0x02
OBJECT = 0x03
MOVIECLIP = 0x04
NULL_VALUE = 0x05
UNDEFINED = 0x06
REFERENCE = 0x07
ECMA_ARRAY = 0x08
OBJECT_END = 0x09
STRICT_ARRAY = 0x0a
DATE = 0x0b
LONG_STRING = 0x0c
UNSUPPORTED = 0x0d
RECORD_SET = 0x0e
XML_OBJECT = 0x0f
TYPED_OBJECT = 0x10
Binary Format
AMF format for a value/object consists of a type byte (see above) followed by zero or more bytes. This section describes the bytes following the type byte for various types.
NUMBER (type byte: 0x00)
Numbers are stored as 8 byte (big endian) float double. On x86 you can just byteswap a double to encode it correctly.
BOOLEAN (type byte: 0x01)
A boolean is encoded in one byte. FIXME: is true sent as 0xff? 0x01?
STRING (type byte: 0x02)
A string is encoded as a 2 byte (big endian) count (number of bytes) followed by that many bytes of text. Note: there is no null terminator.
I think the text is assumed to be UTF-8. Can someone double check me on this?
NULL_VALUE (type byte: 0x05)
A null has zero bytes following the type byte
UNDEFINED (type byte: 0x06)
A undefined has zero bytes following the type byte
OBJECT (type byte: 0x08)
An object is encoded as a series of key/value pairs. The key is encoded as a STRING (above) WITH NO TYPE BYTE, and the value is any AMF value.
The object encoding is terminated by 0x000009 (that is a zero length string key, followed by the OBJECT_END type byte described below.
OBJECT_END (type byte: 0x09)
This is not really a value, but a marker for the end of an OBJECT. See above.
STRICT_ARRAY (type byte: 0x0a)
This is the encoding for arrays such as ["foo", "bar", 1, 2, 3]. For a hash (a set of key/value pairs) you'll need to use OBJECT above.
An array is encoded as 4 byte (big endian) integer which is the number of elements in the array, followed by that many AMF values.
That's it. There's no terminator of any kind.
Use in shared object files
While most AMF objects are just a value, there is a special variation used by shared object files for properties. Rather than start with the type field, followed by the length, it starts with a byte count, then the name, and then the regular AMF type field, the length, and then the data.
3.4 客戶(hù)端和服務(wù)器的連接過(guò)程
3.4.1客戶(hù)和服務(wù)器的握手
?
?? Flash Player 以系統(tǒng)時(shí)間作為種子通過(guò)某種算法生成的數(shù)字簽名,大小是 1537 字節(jié)向服務(wù)器發(fā)起第一次握手,服務(wù)器根據(jù)客戶(hù)端的數(shù)字簽名產(chǎn)生一個(gè) 3073 字節(jié)的驗(yàn)證包,給客戶(hù)端,客戶(hù)端在接受到服務(wù)器的回應(yīng)以后會(huì)發(fā)送一個(gè) 1536 字節(jié)的回復(fù)。
具體的流程:
發(fā)送第一次握手包 handshark1
接收第二次握手包 handshark2
發(fā)送的三次握手包 handshark3
第一個(gè)握手包 handshark1 和服務(wù)器的回復(fù)握手包 handshark2 都是以 0X03 開(kāi)頭。這三次握手不是 RTMP 協(xié)議本身的內(nèi)容,所以在這并沒(méi)有包含 RTMP? 的協(xié)議頭。是服務(wù)器的廠家自己產(chǎn)品做驗(yàn)證用的,嚴(yán)格的說(shuō)就是你必須用? Adobe 的客戶(hù)端和服務(wù)器才能使用我的協(xié)議。
3.4.2客戶(hù)和服務(wù)器通信
?? 具體連接和請(qǐng)求視頻的過(guò)程
發(fā)送 rtmp_connect 命令
. 發(fā)送本地帶寬消息 . 默認(rèn)是 125000
服務(wù)器返回服務(wù)器帶寬信息
服務(wù)器返回本地帶寬信息
服務(wù)器返回連接成功消息 "NetConnection.Connect.Success"
客戶(hù)端發(fā)送創(chuàng)建流請(qǐng)求 encodeCreateStreamPacket
服務(wù)器返回創(chuàng)建流成功消息
客戶(hù)端發(fā)送播放文件消息 Rtmp_Play
服務(wù)器返回 TYPE_CHUNK_SIZE 消息
服務(wù)器返回開(kāi)始播放消息 "NetStream.Play.Start"
服務(wù)器返回視頻信息 (TYPE_STREAM_METADATA) ,包括大小,寬高,速率等等信息--文件長(zhǎng)度可以在這里推算出來(lái)
RTMP 的凈核決定了內(nèi)容服務(wù), adobe 的服務(wù)器采用的 AMF 格式的字串命令來(lái)控制視頻的傳輸和播放,具體的字串命令信息如下:(注:字串的定義有廠家( adobe )自己定義,只要滿(mǎn)足 AMF 的格式就可以)
?
?
NetConnection.Call.Failed
NetConnection.Call.BadVersion?
NetConnection.Connect.AppShutdown
NetConnection.Connect.Closed
NetConnection.Connect.Rejected
NetConnection.Connect.Success
NetStream.Clear.Success
NetStream.Clear.Failed
NetStream.Publish.Start
NetStream.Publish.BadName
NetStream.Failed
NetStream.Unpublish.Success
NetStream.Record.Start
NetStream.Record.NoAccess
NetStream.Record.Stop
NetStream.Record.Failed
NetStream.Play.InsufficientBW
NetStream.Play.Start
NetStream.Play.StreamNotFound
NetStream.Play.Stop
NetStream.Play.Failed
NetStream.Play.Reset
NetStream.Play.PublishNotify
NetStream.Play.UnpublishNotify
NetStream.Data.Start
Application.Script.Error
Application.Script.Warning
Application.Resource.LowMemory
Application.Shutdown
Application.GC
Play
Pause
demoService.getListOfAvailableFLVs
getStreamLength
connect
app
flashVer
swfUrl
tcUrl
fpad
capabilities
audioCodecs
audioCodecs
videoCodecs
videoFunction
pageUrl
createStream
deleteStream
duration
framerate
audiocodecid
audiodatarate
videocodecid
videodatarate
height
width
3.4.2數(shù)據(jù)的萃取
????? 在服務(wù)器返回開(kāi)始播放消息 "NetStream.Play.Start" 之后,服務(wù)器就會(huì)開(kāi)始給客戶(hù)端傳輸數(shù)據(jù)了,一般數(shù)據(jù)的萃取都是先解析協(xié)議的頭,然后根據(jù)協(xié)議頭中數(shù)據(jù)類(lèi)型和凈核長(zhǎng)度就可以把數(shù)據(jù)部分取出, RTMP 協(xié)議也是這樣。
struct RTMP_HEAD
{
????????? char cChannelid : 6;// 第一個(gè)字節(jié)的后 6 位
????????? char cCheadsize ; // 第一個(gè)字節(jié)的頭兩位
????? char cTimer[3];? // 三個(gè)字節(jié)表示的時(shí)間信息
????? char cLength[3]; // 三個(gè)字節(jié)表示的長(zhǎng)度
????? char cDatatype; // 數(shù)據(jù)類(lèi)型
????? char sStreamid[4]; // 流標(biāo)識(shí)
}
????? 首先判斷 cDatatype 是那種類(lèi)型,然后根據(jù)不同的類(lèi)型進(jìn)行萃取數(shù)據(jù)部分,進(jìn)行不同的處理,獲取視頻的數(shù)據(jù)的方式先看是否是一下的類(lèi)型:
0×08? Audio Data? packet containing audio?
0×09? Video Data? packet containing video data?
?
根據(jù)凈核的長(zhǎng)度讀取出內(nèi)存中的音視頻數(shù)據(jù),這里的音視頻數(shù)據(jù)是有一定編碼格式的數(shù)據(jù),這個(gè)取決于應(yīng)用的具體配置, Flash play 使用的是 FLV 的格式。要對(duì)這部分?jǐn)?shù)據(jù)進(jìn)行存取,還有做一部分工作,對(duì) FLV 的視頻數(shù)據(jù)進(jìn)行去殼,取出數(shù)據(jù)保存文件就可以了。
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/chenyanxu/archive/2009/09/02/4511087.aspx