實時消息傳輸協議 RTMP(Real Time Messaging Protocol)

原文: http://blog.csdn.net/defonds/article/details/17403225javascript

譯序:本文是維基百科關於 RTMP 的解釋, 關於 RTMP 官方規範參見 RTMP 規範,關於 RTMP 官方規範的中文版,參見《Adobe 官方公佈的 RTMP 規範》。如下是維基百科原文:php

        實時消息傳輸協議(RTMP)最初是由 Macromedia 爲互聯網上 Flash player 和服務器之間傳輸音頻、視頻以及數據流而開發的一個私有協議。Adobe 收購 Macromedia 購之後,公佈了這個協議的一部分,以備公共使用。html

        RTMP 協議有多個變種:
        1. 工做在 TCP 協議之上,並使用默認端口號 1935 的明文協議。
        2. RTMPS 使用 TLS/SSL 鏈接的 RTMP 協議。
        3. RTMPE 使用 Adobe 本身的安全機制的加密 RTMP。雖然它的實現細節是私有的,但使用的是行業標準加密原語。RTMPE 的設計是有缺陷的,它自己並不提供實際的安全。
        4. RTMPT 封裝在 HTTP 請求內部以穿越防火牆的協議。RTMPT 經常使用於創建 TCP 端口 80 和 443 的請求以繞開不少公司的流量過濾。封裝的會話中可能會攜帶純 RTMP、RTMPS 或者 RTMPE 包。java

        儘管 RTMP 協議的本意是一個用於播放 Flash 視頻的協議,但它也每每用於其餘應用,好比 Adobe LiveCycle數據服務。linux

 

        基本操做
        RTMP(RTMFP 除外)是一個基於 TCP 的、持久鏈接並提供低延遲通訊的協議。爲了可以順利地傳輸流,而且傳遞儘量多的信息,RTMP 對流進行分段,客戶端和服務器能夠對分段長度進行協商,儘管有時分段長度是不變的:對於音頻數據默認分段長度是 64 字節,視頻數據和大部分其餘數據類型默認分段長度是爲 128 字節。來自不一樣流的段會被隔離,並對單一鏈接的段進行合成。對於比較長的數據塊,RTMP 會在每一段中攜帶一個單字節頭,因此開銷很小。然而,事實應用中,不一樣的段並不互相交叉。交叉和合成是在數據包層完成的,RTMP 包穿過不一樣的活躍通道進行交叉,用這種方法來保證每一個通道都知足各自的帶寬、延遲以及其餘一些服務質量的需求。這種模型下交叉的 RTMP 包被視爲不可分割的,而且在分段級別是不交叉的。
        RTMP 定義了一些虛擬通道,經過它們能夠發送和接收 RTMP 包,而且這些通道彼此是獨立運做的。例如,可能會有一個用於處理 RPC 請求和響應的通道,一個用於視頻流數據的通道,一個用於音頻流數據的通道,一個用於帶外控制信息(分段長度協商,等等)的通道,等等。在一個典型的 RTMP 會話中,在任意給定時間內,可能會有幾個通道是同時活躍的。當 RTMP 數據被編碼時,會產生一個包頭。包頭定義了其餘一些事項,要發送到通道的 id,這一包產生時的 timestamp (若是須要的話),以及這一包的有效負載。包頭後緊跟這一包實際負載的內容,包的內容是在發送給鏈接前根據當前協商好的分段長度分割好的。包頭本身不會分段,而且包頭的長度也不會被計入這一包第一個分段的長度中去。換句話說,分段的主題僅僅是 RTMP 的包負載(音頻數據)。
        更高一層講,RTMP 壓縮 MP3 或者 AAC 音頻和 FLV1 視頻多媒體流,並使用 AMF (Action Message Format) 協議進行遠程方法調用 (RPCs)。所需的 RPC 服務都是異步的,它們使用單一的 client/server request/response 模型,所以不須要實時通訊。
        加密
        RTMP 會話可使用如下兩種方法的任意一種進行加密:
        使用行業標準 TLS/SSL 機制。底層的 RTMP 會話唄簡單地封裝在一個普通的 TLS/SSL 會話中。
        使用 RTMPE,將 RTMP 會話封裝在一個輕量級的加密層裏。
        廣泛認爲,會話開始時的 TLS/SSL 握手是很是計算密集型的。Adobe 開發了 RTMPE 做爲一個輕量級的替代,給提供加密服務的高流量的站點一個實用的選擇。Adobe 通告 RTMPE 做爲一個安全內容傳遞的方法,以免模擬客戶端的操做,這種說法是錯誤的。RTMPE 僅使用了 Diffie-Hellman 機制,沒有提供任何一方的身份驗證,這很容易在會話初始化時受到中間人攻擊。
        HTTP 隧道
        在 RTMP 隧道 (RTMPT) 中,RTMP 數據被密封起來並經過 HTTP 進行交換,來自客戶端(在這種狀況下客戶端是爲 media player)的信息發送給服務器上的端口 80 (HTTP 默認端口號)。
        因爲 HTTP 頭的緣故,RTMPT 中的信息要比等效的非通道的 RTMP 信息大,在非通道 RTMP 不能夠的場景中,好比當客戶端處於一個阻止非 HTTP 和 非 HTTPS 網絡流通時,RTMPT 能夠便利地使用。
        這個協議經過使用 POST url 發送命令和使用 POST 體發送 AMF 消息進行工做。例子:web

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. POST /open/1 HTTP/1.1  

 

        用於打開一個鏈接。數組

 

        規範文檔
        Adobe 公開聲明的規範是 2009 年 6 月 15 日發佈的 RTMP specification。那個規範,忽略了(應該說沒有公開) 協議實現的關鍵細節。很難單單根據發佈的規範將 RTMP 協議整合進咱們的程序裏,太多必不可少的細節被忽略了,咱們只可以經過學習實現了這個協議的應用 (好比 librtmp),以及根據測試 TCP/IP 數據包捕獲,來判定其不多的細節。
        Adobe 關於使用這一協議的 license 要求 RTMP 服務器的實現知足這一規範。
        Adobe 發佈的規範中缺乏的細節包括:瀏覽器

  • 關於 RTMP 握手沒有隻言片語的描述。若是(關於握手)作的不正確,服務器的實現將沒法傳遞 H.264/AAC 內容。若是握手錯誤,Flash player 會默默地接收 H.264 內容失敗。可是全部的客戶端實現可以正常工做,由於 RTMP 服務器在這方面比較寬容(包括 FMS)。
  • 發送的塊只以最大塊大小發送;超出那個大小的塊仍會被髮送,這個塊帶有整個塊大小的頭,可是當超出最大塊大小後,一個類型爲 4 的塊頭會被髮送,緊跟其後的是這一塊被分割出來的下一部分。
  • 關於流的管理信息的解釋缺失(31 和 32)。FMS 會時不時發送這些包。

        

  數據包格式緩存

        數據包由客戶端和服務器之間創建的 TCP 鏈接進行發送。數據包包含一個頭和一個體,至於鏈接和控制命令使用 AMF(Action Message Format)編碼。頭分爲基本報頭(在圖中顯示爲分離出來的那塊)和塊消息報頭。基本報頭是數據包惟一不變的部分,經常由一個複合字節組成,兩個有效位表明塊類型(規範中的格式),其他的組成了流 id。根據前者的值,一些消息頭字段能夠被忽略掉,這些字段由前面的數據包根據後面的值派生出來,基本報頭可使用兩個額外字節進行擴展(圖中的狀況總共有三個字節)。塊消息報頭包含 meta-data 信息,好比消息大小(以字節爲單位),Timestamp 以及消息類型。最後一個值是一個單獨的字節,它定義了這個包是一個音頻包,或者視頻包,或者命令以及 "低層次" RTMP 包好比一個 RTMP Ping。安全

RTMP Packet Diagram

        如下示例,一個 flash 客戶端執行如下代碼時:

[javascript]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. var stream:NetStream = new NetStream(connectionObject);  


        這將生成如下塊:

Hex Code ASCII
03 00 0b 68 00 00 19 14 00 00 00 00 02 00 0C 63 72 65 61 74 65 53 74 72 65 61 6D 00 40 00 00 00 00 00 00 00 05 . . @ I . . . . . . . . . . . . c r e a t e S t r e a m . @ . . . . . . . .


        這一包以一個字節的基本報頭開始,兩個有效位(b00000011) 定義了塊頭類型 0,其他部分(b00000011) 定義了塊的流 ID 是 3。頭類型會有 4 種可能的值,他們的意義分別是:

  • b00 = 12 字節頭(完整的頭)。
  • b01 = 8 字節 - 像類型 b00。不包含消息 ID(後四個字節)。
  • b10 = 4 字節 - 包含有基本報頭和 timestamp (3 個字節)。
  • b11 = 1 字節 - 只包含有基本頭。

        最後一個類型 (b11) 經常使用於聚合信息的狀況,在上面的例子中,第二個消息會以 id 爲 0xC3 (b11000011) 起始,意味着全部消息報頭字段要以流 ID 爲 3 的消息傳遞(偏偏是其上的消息)。六個最低的有效位組成流 ID,取值範圍是 3 到 65599。一些值具備特殊意義,好比 1 表明一個擴展的 ID 格式,這時會有兩個字節跟隨。值爲 2 用於底層的消息,例如 Ping 和設置客戶端帶寬。
        接下來的 RTMP 報頭的字節(包含以上數據包例子中的值)詳解以下:

  • 字節 #1 (0x03) = 塊頭類型。
  • 字節 #2-4 (0x000b68) = Timestamp。
  • 字節 #5-7 (0x000019) = 包長度 - 在這個例子中是 0x000019 = 25 字節。
  • 字節 #8 (0x14) = 消息類型 ID - 0x14 (20) 定義了一個 AMF0 編碼的命令消息。
  • 字節 #9-12 (0x00000000) = 消息流 ID。這個以小端排序(很奇怪)。

        消息類型 ID 字節定義了當前包是否包含音頻/視頻數據,一個遠程對象或者一個命令。一些可能的值以下:

  • 0x01 = 設置包大小消息。
  • 0x04 = Ping 消息。
  • 0x05 = 服務器帶寬。
  • 0x06 = 客戶端帶寬。
  • 0x08 = 音頻包。
  • 0x09 = 視頻包。
  • 0x11 = 一個 AMF3 類型命令。
  • 0x12 = 調用 (onMetaData 信息會這樣發送)。
  • 0x14 = 一個 AMF0 類型的命令。

        緊跟報頭,0x02 表示一個大小爲 0x000C 的串,0x63 0x72 ... 0x6D ("createStream" 命令)。其後是 0X00 表明 ID 爲 2.0 的事務。最後一個字節是 0x05 (null) 表示沒有參數。
        Invoke 消息結構 (0x14, 0x11)
        以上所述的幾種消息類型,好比 Ping 和設置客戶端/服務端帶寬,被認爲底層 RTMP 協議消息,它們不使用 AMF 編碼格式。換句話說,命令消息,不管是 AMF0 (Message Type of 0x14) 仍是 AMF3 (0x11),使用這種格式:

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. (String) <Command Name>  
  2. (Number) <Transaction Id>  
  3. (Mixed)  <Argument> ex. Null, String, Object: {key1:value1, key2:value2 ... }  


        事務 id 用於有回覆的命令。這個值能夠是上面例子中的一個字符串,也能夠是一個或者多個對象,每一個由一個鍵值對組成,鍵值對的鍵常常編碼爲字符串值,鍵值對的值能夠是任意 AMF 數字類型,包括複雜的類型,好比數組。
        Ping 消息結構 (0x04)
        Ping 消息不是 AMF 編碼。它們以一個流 Id 起始,帶有一個完整 (類型 0) 報頭,並有一個類型爲 0x04 的消息。報頭後面緊隨六個字節:

  • #0-1 - Ping 類型。
  • #2-3 - 第二個參數 (對於特定的 Ping 類型有意義)。
  • #4-5 - 第三個參數 (同樣)。

        消息體的前兩個字節定義了 Ping 的類型,有六種可能取到的值。

  • 類型 0 - 清除流:當鏈接已創建而沒有帶有更多數據時發送。
  • 類型 1 - 清除緩存。
  • 類型 3 - 客戶端緩存時間。第三個參數以毫秒爲單位持有這個值。
  • 類型 4 - 重置流。
  • 類型 6 - 從服務器 Ping 客戶端。第二個參數是當前時間。
  • 類型 7 - 客戶端回覆的 Pong。第二個參數是客戶端接收到 Ping 的時間。

        Pong 是 Ping 回覆的名字,它使用以上介紹的值。
        ServerBw/ClientBw 消息結構 (0x05, 0x06)
        這個關聯到和客戶端向上流、服務器向下流比特率相關的消息。消息體由 4 個字節組成,表示帶寬的值,它可能有一個擴展字節來設置 Limit 類型。這個能夠有三種可能的值:hard、soft 或者 dynamic (就是 soft 或者 hard 任一)。
        設置塊大小 (0x01)
        這個值能夠在報體的四個字節裏接收到。存在默認值 128 字節,當你想要改變默認值時纔會發生這個消息。
        協議
        握手

        創建 TCP 鏈接後,RTMP 鏈接會在兩端交互三個包的握手以後創建(這在官方文檔裏也被引用爲塊)。在官方規範中,這裏描述爲客戶端發送包 C0-2,服務器端發送包 S0-2,不要和 RTMP 包混淆,RTMP 包只會在握手完成以後才能交互。這些包擁有本身的結構,C1 包含一個設置 "epoch" timestamp 的字段,可是由於這個能夠設置爲 0,正如第三方實現過的,這個包能夠被簡化。客戶端經過發送一個帶有表明現有協議版本號常數值 0x03 的 C0 包初始化鏈接。它能夠直接跟隨 C1 而無須等待接收到 S0,它帶有 1536 字節,前四個字節表明 timestamp,其餘的隨意 (第三方實現中能夠將其設置爲 0)。C2 和 S2 分別是 S1 和 C1 的回聲,接收到它們以後,握手才被認爲結束。
RTMP Handshake Diagram
        鏈接
        這一點上,客戶端和服務器會經過交互 AMF 編碼的消息進行協商鏈接。這些包含關係到創建鏈接所須要的變量的鍵值對。一個來自客戶端的消息例子以下:

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. (Invoke) 「connect」  
  2. (Transaction ID) 1.0  
  3. (Object1) { app: 「sample」, flashVer: 「MAC 10,2,153,2」, swfUrl: null,  
  4.               tcUrl: 「rtmpt://127.0.0.1/sample 「, fpad: false,  
  5.               capabilities: 9947.75 , audioCodecs: 3191, videoCodecs: 252,  
  6.               videoFunction: 1 , pageUrl: null, objectEncoding: 3.0 }  


        FMS 和其餘市縣使用一個 "app" 的概念來概念化爲音頻/視頻和其餘內容定義一個容器,具體實現是,在服務根目錄下的一個文件夾,其下含有將要被流化的媒體文件。第一個變量含有這一 app 的名 "sample",這個是由 Wowza 服務器用於測試所提供的名字。flashVer 字符串和 Action-script 的 getversion() 方法返回的值同樣。audioCodec 和 videoCodec 使用 double 編碼,它們的含義能夠在原始規範裏找到。videoFunction 的值是 true,在這裏明顯是 SUPPORT_VID_CLIENT_SEEK 變量。特別有趣的是 objectEncoding,它定義了通訊的其他部分是否會使用擴展的 AMF3 格式。由於當前默認版本爲 3,flash 客戶端必須被以 Action-script 代碼顯式告知去使用 AMF0。服務器會用 ServerBW 回覆,一個 ClientBW 和一個 SetPacketSize 消息序列,最終跟隨一個 Invoke,用一個實例消息。

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. (Invoke) 「_result」  
  2. (transaction ID) 1.0  
  3. (Object1) { fmsVer: "FMS/3,5,5,2004", capabilities: 31.0, mode: 1.0 }  
  4. (Object2) { level: 「status」, code: 「NetConnection.Connect.Success",  
  5.                    description: 「Connection succeeded」,  
  6.                    data: (array) { version: 「3,5,5,2004」 },  
  7.                    clientId: 1728724019, objectEncoding: 3.0 }  


        上面的一些值會被連續加載到一個通用的 Action-script Object,這個對象隨後被傳遞給 NetConnection 事件監聽者。clientId 將會爲這個鏈接開啓的會話創建一個編號。Object 編碼必須匹配前面設定的值。
        播放視頻
        要開始一個視頻流,客戶端發送一個由一個 ping 消息跟隨的 "createStream" 調用,其後再跟隨一個以文件名爲參數的 "play" 調用。服務器隨後以一系列的 "onStatus" 命令和帶有視頻數據的 RTMP 消息進行回覆。

        鏈接創建之後,媒體由封裝爲 FLV tag 內容的 RTMP 消息對類型 8 和 類型 9 的音頻和視頻交疊發送。

 

        HTTP 隧道 (RTMPT)
        這一節講解 RTMP 的 HTTP 隧道式版本。它交互在端口 80,並在 HTTP POST 請求和回覆內部傳遞 AMF 數據。鏈接的時序以下:

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. POST /fcs/ident2 HTTP/1.1  
  2. Content-Type: application/x-fcs\r\n  
  3.   
  4. HTTP/1.0 404 Not Found  
  5.   
  6. POST /open/1 HTTP/1.1  
  7. Content-Type: application/x-fcs\r\n  
  8.   
  9. HTTP/1.1 200 OK  
  10. Content-Type: application/x-fcs\r\n  
  11.     1728724019  


        第一個請求有一個路徑 /fcs/ident2,正確的返回是 404 沒法查找錯誤。客戶端而後發送了一個 /open/1 請求,服務器以附加一個表明 session 標識的隨機數的 200 ok 返回。在以上例子中,返回體中返回 1728724019。

[plain]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
 
  1. POST /idle/1728724019/0 HTTP/1.1  
  2. HTTP/1.1 200 OK  
  3.    0x01  


        今後開始,/idle/<session id>/<sequence #> 會輪詢請求,session id 是由服務器生成並返回,sequence 是一個爲以 1 開始之後每次請求遞增的數字。正確的回覆是一個報體中帶有指示內部時間的整數,200 OK。AMF 數據經過 /send/<session id>/<sequence #> 發送。
        軟件實現
        客戶端軟件

        最普遍採用的 RTMP 客戶端軟件是 Adobe Flash Player,它可以支持來自 RTMP 服務器的音視頻流的回放(當它被安裝爲一個 web 瀏覽器的插件時)。
        只能部分支持 RTMP 的客戶端軟件寶庫開源的 media player XBMC,它提供了播放 RTMP (不包括 RTMPE) 流的初步支持。
        開源的命令行工具 rtmpdump 用於回放或者將整個 RTMP 流 (包括 Adobe 用於加密的 RTMPE) 保存到磁盤。RTMPdump 能夠運行在 Linux、Android、Solaris、MacOSX 以及大部分其餘的 Unix 派生操做系統,固然也能夠運行在微軟 Windows。最初支持全部 32 位版本的 Windows 系統,包括 Windows 98,從版本 2.2 起,這款軟件只能泡在 Windows XP 或者更高版本的 Windows 系統之上(儘管早期版本保持功能齊全)。
        RTMPdump 的一個分叉,沒有包含 Adobe 聲稱違反了美國 DMCA 的 RTMPdump 代碼,以 FLVstreamer 發佈了。它的開發是 2008 年 Adobe 抵制 RTMPdump 的一個直接反應。FLVstreamer 能夠未來自任意一臺 RTMP 服務器的音頻流或者視頻流保存到磁盤,只要流沒有開啓 RTMPE。FLVstreamer 運行於 Windows XP 或者更高版本的 Windows 系統之上,但不支持早期版本的 Windows。
        2009 年十月,在美國之外的國家,MPlayer 網站 從新啓動了 RTMPdump 的研發。現有版本大大改進了功能,而且使用了 C 語言重寫,大大利用了 C 的優點。尤爲是,主要功能被內置到一個庫 (librtmp) 中,其餘程序能夠很容易使用這些功能。RTMPdump 的開發者們也爲其餘一些開源項目 (諸如 MPlayer、FFmpeg、XBMC、cURL、VLC) 提供了 librtmp 的支持。這些項目對 librtmp 的使用,擁有了徹底 RTMP 的支持。
        開源的 Gnash,一個在 Linux 平臺上對於 Macromedia Flash Player 的替代,擬就爲 Linux 支持 RTMP streaming。
        服務器端軟件
        一些全面執行 RTMP 的服務器有:

  • Adobe FMS
  • Adobe 生命週期數據服務。
  • 亞馬遜 S3 和亞馬遜 Cloudfront 可使用 RTMP 流。
  • haXeVideo 是一個徹底由 haXe 語言開發的多流 FLV 流媒體服務器。
  • RealNetworks 的 Helix Universal Server 能夠支持 RTMP、RTMPT 和 RTMPS 流的直播和點播。
  • Red5 Media Server 是一個 Java 開源項目,爲 Adobe Flash Player 和其餘客戶端技術提供了一個強大的視頻流和多用戶解決方案。
  • Erlyvideo 具備普遍的功能:不只僅是文件流化,並且可使用 RTMP 對 MPEG-TS 或者 Shoutcast 爲 flash 客戶端從新流化。
  • Unreal Media Server 支持實時和緩存 RTMP 流的直播。
  • Wowza Media Server
  • WebORB Integration Server (交流版和雲版,爲 .NET 和 Java 企業版提供了 RTMP/RTMPT/RTMPS 消息和媒體流化支持)。
  • FreeSWITCH RTMP 流媒體 mod_rtmp 可用,並容許和其餘 VoIP 協議 (SIP, H.323) 互連。
  • FFmpeg
  • Nginx with RTMP Module
  • XSplit Broadcaster

        探索和研發

  • crtmpserver 探索者們對 RTMFP 協議進行逆向工程。如今仍是個半成品。
  • Blue5 - 一個意圖建立開源版本的 RTMPE 和 RTMFP 的項目。
  • kbmMW 爲 Delphi/C++Builder 支持 RTMP 的企業版多層次開發工具。

        另請參閱

        參考資料

        外部連接

原文連接:http://en.wikipedia.org/wiki/Real_Time_Messaging_Protocol

相關文章
相關標籤/搜索