RTMP協議– AMF消息詳解

一、簡述:

本教程是基於VLC實現的Rtmp服務器與客戶端的播放流程

AMF 命令-命令消息類型

發送端發送時會帶有:

  • 命令的名字,如 connect
  • Transaction ID 表示此次命令的標識
  • Command Object 表示相關參數

接受端收到命令後,會返回以下三種消息中的一種:

  • _result 消息表示接受該命令,對端可以繼續往下執行流程
  • _error 消息代表拒絕該命令要執行的操作
  • method name 消息代表要在之前命令的發送端執行的函數名稱。

這三種迴應的消息都要帶有收到的命令消息中的 Transaction ID 來表示本次的迴應作用於哪個命令。

可以認爲發送命令消息的對象有兩種:

  • 一種是 Net Connection,表示雙端的上層連接
  • 一種是 Net Stream,表示流信息的傳輸通道,控制流信息的狀態,如 Play 播放,Pause 暫停等。

這些命令直接以 AMF 格式數據放置在 Chunk Data 部分。

協議控制消息

這些協議控制消息必須使用消息流ID 0(又稱爲控制流)且在塊流ID 2中發送。協議控制消息收到時立即生效,他們的時間戳會被直接忽略。

二、服務器與客戶端交互流程圖(Play過程)

服務器與客戶端交互流程圖(Play過程)
服務器與客戶端交互流程圖(Play過程)

 

三、具體消息分析

1、Connect(‘stream名’):屬於命令消息類型(c—>s)

        名稱:connect

        作用:客戶端發送 connect 命令到服務器端來請求連接到一個服務器應用的實例

        包結構:(結構跟publish中的connect一致)

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+body size(3byte)+Typeid(1byte)+stream id(4byte) 

  1. Type id可能爲0x14,代表包將採用AMF0方式進行編碼。
  2. Type id也可爲0x11,表示包將採用AMF3方式進行編碼。

         RTMP_body:

                Command Name(命令名字,字符串,設置給 "connect")

                Transaction ID(事務ID,數字,總是設置爲 1)

                Command Object(鍵值對集合標識命令參數)

                Optional User Arguments(用戶自定義的額外信息,可選參數)

                End of objectMarker(0x00 0x00 0x09) (Object的結尾)

 

2、Window Acknowledgement Size:  屬於協議控制消息(C—>S)

        名稱:窗口確認大小。

        作用:客戶端或者服務器端發送這條消息來通知對端發送和應答之間的窗口大小。發送者在發送完窗口大小字節之後期待對端的確認。接收端在上次確認發送後接收到的指示數值後,或者會話建立之後尚未發送確認,必須發送一個確認。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,type id是一定的爲5

         RTMP_body:

                   WindowAcknowledgement Size(4byte)

3、Acknowledgement(C-->S)

在播放過程中客戶端會不斷髮送這個Acknowledgement窗口確認大小,這個可以不處理,但是如果響應錯了,會立馬導致客戶端主動斷開。在各大園中也沒有那個文檔中說明有這個命令,本人按Window Acknowledgement Size:  屬於協議控制消息返回客戶端貌似沒什麼反應,還是照常發送。如有大神知道其中明理希望告知。

 

4、Set peer bandwidth: 屬於協議控制消息(C—>S)(type id=6)

        名稱:設置對端帶寬。

        作用:客戶端或者服務器端發送這一消息來限制其對端的輸出帶寬。對端接收到這一消息後,將通過限制這一消息中窗口大小指出的已發送但未被答覆的數據的數量以限制其輸出帶寬。如果這個窗口大小不同於其發送給 (設置對端帶寬) 發送者的最後一條消息,那麼接收到這一消息的對端應該回復一個窗口確認大小消息。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,type id是一定的爲6

         RTMP_body:

 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    WindowAcknowledgement Size                 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|    Limit type |  
+-+-+-+-+-+-+-+-+   
      Payload for the 'Set Peer Bandwidth' protocol message

                   WindowAcknowledgement Size(4byte)+Limit type(1byte)

        限制類型取以下值之一:

                0 - Hard:對端應該限制其輸出帶寬到指示的窗口大小。

                1 - Soft:對端應該限制其輸出帶寬到指示的窗口大小,或者已經有限制在其作用的話就取兩者之間的較小值。

                2 - Dynamic:如果先前的限制類型爲Hard,處理這個消息就好像它被標記爲 Hard,否則的話忽略這個消息。

5、Set Chunk Size:屬於協議控制消息.(C—>S)

 名稱:設置塊大小。

        作用:協議控制消息 1,設置塊大小,以通知對端一個新的最大塊大小(set chunk size)。默認的最大塊大小是爲 128 字節,但是客戶端或者服務器可以改變這個大小,並使用這一消息對對端進行更新。例如,假定一個客戶端想要發送一個 131 字節的音頻數據,當前塊大小是默認的 128。在這種情況下,客戶端可以發送這種消息到服務器以通知它塊大小現在是 131 字節了。這樣客戶端就可以在單一塊中發送整個音頻數據了。最大塊大小設置的話最少爲 128 字節,包含內容最少要一個字節。最大塊大小由每個方面 (服務器或者客戶端) 自行維護。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

         RTMP_body: 4個字節標識Chunk塊大小

注:從FMS服務器發出來的Chunk大小來分析,其大多都是使用的0x1000==4096,至於爲什麼我也不清楚了。如果在過程中不發送該消息,則Wireshark分析不出消息,全是Unknown。再者如果不發該消息,視頻如果關鍵幀比較大,例如25寸的電腦屏幕一個關鍵幀就200萬左右字節,分包發送後客戶端後是不被客戶端認可的,因爲對方無法解析出相應的音視頻數據。如果是電腦的前置攝像頭的話流就比較小,大約也就1萬多不到2萬字節,直接設置成6萬(也是觀察得知的數值),直接整個流發送也是可以的。

 

6、Stream begin 0:屬於用戶控制消息.(C—>S)

        作用:服務器發送這個事件來通知客戶端一個流已就緒並可以用來通信。默認情況下,這一事件在成功接收到客戶端的應用連接命令之後以 ID 0 發送。這一事件數據爲 4 字節,代表了已就緒流的流 ID。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                type id是一定的爲4

                csid是一定的爲2

                stream id是一定的爲0

                並且timestamp將被忽略

         RTMP_body:

                   Eventtype:stream begin(0)(2byte)+4byte的數據 (0x00,0x00,0x00,0x00)            

 

 

 7、_result(netconnect.connect.success):屬於命令消息類型(響應)(S-->C)

名稱:服務器應答命令。

作用:服務器端向客戶端發送的關於之前客戶端向服務器端請求的命令的響應結果。對方發送控制命令後比如Connect,要返回對應的響應比如_result、或者_error(Get Stream Length 的時候FMS返回的就是_error)。對應的Transaction ID要跟收到的命令的Transaction ID對應上,否則響應無效。如果不發送該消息,對端會一直等待。

        包結構:

     RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

其中,Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

字段名

類型

描述

Command Name

字符串

_result 或者 _error;表明回覆是一個結果還是錯誤。

Transaction ID

數字

響應所屬的命令的 ID。

Command Object

對象

如果存在一些命令信息要設置這個對象,否則置空。

Stream ID

數字

返回值要麼是一個流 ID 要麼是一個錯誤信息對象。

 注意:在VLC播放中服務器收到connect命令後,要發送如下_result命令:

實際輸入如下(從Wireshark中複製出來的實際數據以便交流分析):

0000   03 00 00 00 00 00 f0 14 00 00 00 00 02 00 07 5f
0010   72 65 73 75 6c 74 00 3f f0 00 00 00 00 00 00 03
0020   00 06 66 6d 73 56 65 72 02 00 0d 46 4d 53 2f 33
0030   2c 35 2c 32 2c 36 35 34 00 0c 63 61 70 61 62 69
0040   6c 69 74 69 65 73 00 40 3f 00 00 00 00 00 00 00
0050   04 6d 6f 64 65 00 3f f0 00 00 00 00 00 00 00 00
0060   09 03 00 05 6c 65 76 65 6c 02 00 06 73 74 61 74
0070   75 73 00 04 63 6f 64 65 02 00 1d 4e 65 74 43 6f
0080   6e 6e 65 63 74 69 6f 6e 2e 43 6f 6e 6e 65 63 74
0090   2e 53 75 63 63 65 73 73 00 0b 64 65 73 63 72 69
00a0   70 74 69 6f 6e 02 00 15 43 6f 6e 6e 65 63 74 69
00b0   6f 6e 20 73 75 63 63 65 65 64 65 64 2e 00 0e 6f
00c0   62 6a 65 63 74 45 6e 63 6f 64 69 6e 67 00 00 00
00d0   00 00 00 00 00 00 00 04 64 61 74 61 08 00 00 00
00e0   00 00 07 76 65 72 73 69 6f 6e 02 00 09 33 2c 35
00f0   2c 32 2c 36 35 34 00 00 09 00 00 09

8、_result(netconnect.connect.success):屬於命令消息類型(S-->C)

        名稱:服務器應答命令。

        作用:服務器端向客戶端發送的關於之前客戶端向服務器端請求的命令的響應結果。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

字段名

類型

描述

Command Name

字符串

_result 或者 _error;表明回覆是一個結果還是錯誤。

Transaction ID

數字

響應所屬的命令的 ID。

Command Object

對象

如果存在一些命令信息要設置這個對象,否則置空。

Stream ID

數字

返回值要麼是一個流 ID 要麼是一個錯誤信息對象。

 注:本條消息與上面那條消息命令雖是同一種命令,但是內容不一樣位置也不一樣。上面那條本人從抓包分析中得知是響應Connect的,本條是響應Create Stream的。

9、onBWDone():屬於命令消息類型(S-->C)

       名稱:服務器應答命令。

作用:服務器端向客戶端發送的關於之前客戶端向服務器端請求的命令的響應結果。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

注:onBwDone命令本人沒有處理(也就是作爲服務端沒有發送)但是沒有影響,具體作用不太瞭解。

10、creatStream(): 屬於協議控制消息(C—>S)

        名稱:createStream

        作用:客戶端發送這一命令到服務器端爲消息連接創建一個邏輯通道。音頻、視頻和元數據使用 createStream 命令創建的流通道傳輸。

包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

字段名

類型

描述

Command Name

字符串

命令名。設置給 "createStream"。

Transaction ID

數字

命令的事務 ID。

Command Object

對象

如果存在一些命令信息要設置這個對象,否則置空。

 

11、set Buffer Length:屬於用戶控制消息.(C—>S)

        名稱:窗口確認大小。

        作用:客戶端發送這一事件來通知服務器端用於緩存流中任何數據的緩存大小 (以毫秒爲單位)。這一事件在服務器端開始處理流之前就發送。這一事件數據的前 4 個字節代表了流 ID 後 4 個字節代表了以毫秒爲單位的緩存的長度。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,type id是一定的爲4.csid是一定的爲2.stream id是一定的爲0。並且timestamp將被忽略。

         RTMP_body:

                   Eventtype:Set Buffer Length(3)(2byte)+ 流ID(4byte) + 緩存的長度(以毫秒爲單位,4byte)

 

12、Play(‘app名’):屬於命令消息類型(c—>s)

        名稱:play

        作用:客戶端發送這一命令到服務器端以播放流。也可以多次使用這一命令以創建一個播放列表。

        如果你想要創建一個動態的播放列表這一可以在不同的直播流或者錄製流之間進行切換播放的話,多次調用 play 方法,並在每次調用時設置Reset的值爲 false。相反的,如果你想要立即播放指定流,需要將其他等待播放的流清空,併爲將Reset設爲true。

         包結構:(結構跟publish中的connect一致)

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+body size(3byte)+Typeid(1byte)+stream id(4byte)

                其中:Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

字段名

類型

描述

Command Name

字符串

命令名。設爲 "play"。

Transaction ID

數字

事務 ID設爲 0。

Command Object

Null

命令信息不存在。設爲 null類型。

Stream Name

字符串

要播放流的名字。要播放視頻 (FLV)文件,使用沒有文件擴展名的名字對流名進行定義 (例如,"sample")。要重播 MP3或者 ID3,你必須在流名前加上 mp3:例如,"mp3:sample"。要播放 H.264/AAC文件,你必須在流名前加上 mp4:並指定文件擴展名。例如,要播放 sample.m4v文件,定義"mp4:sample.m4v"。

Start

數字

一個可選的參數,直播流交互過程中沒有此字段,可能是沒有添加。該字段以秒爲單位定義開始時間。默認值爲 -2,表示用戶首先嚐試播放流名字段中定義的直播流。如果那個名字的直播流沒有找到,它將播放同名的錄製流。如果沒有那個名字的錄製流,客戶端將等待一個新的那個名字的直播流,並當其有效時進行播放。如果你在 Start字段中傳遞-1,那麼就只播放流名中定義的那個名字的直播流。如果你在 Start字段中傳遞 0或一個整數,那麼將從 Start 字段定義的時間開始播放流名中定義的那個錄製流。如果沒有找到錄製流,那麼將播放播放列表中的下一項。

Duration

數字

一個可選的參數,以秒爲單位定義了回放的持續時間。默認值爲 -1。-1值意味着一個直播流會一直播放直到它不再可用或者一個錄製流一直播放直到結束。如果你傳遞 0 值,它將只播放單一一幀,因爲播放時間已經在錄製流的開始的Start字段指定了。假定定義在 Start字段中的值大於或者等於0。如果你傳遞一個正數,將播放 Duration字段定義的一段直播流。之後,變爲可播放狀態,或者播放 Duration 字段定義的一段錄製流。(如果流在 Duration字段定義的時間段內結束,那麼流結束時回放結束)。如果你在 Duration字段中傳遞一個 -1以外的負數的話,它將把你給的值當做 -1處理。

Reset

布爾

一個可選的布爾值或者數字定義了是否對以前的播放列表進行 flush。

 

13、onStatus(‘NetStream.Play.Reset’):屬於命令消息類型(S-->C)

        名稱:onStatus

        作用:服務器端使用"onStatus" 命令向客戶端發送 NetStream 狀態。

        包結構:

         RTMP_header:

                fmt(2bit)+csid(6bit-22bit)+timestamp(3byte)+bodysize(3byte)+Type id(1byte)+stream id(4byte)

                其中,Type id可能爲0x14,代表包將採用AMF0方式進行編碼。也可以爲0x11,此時表示包將採用AMF3方式進行編碼。

         RTMP_body:

字段名

類型

描述

Command Name

字符串

命令名 "onStatus"。

Transaction ID

數字

事務 ID 設置爲 0。

Command Object

Null

onStatus 消息沒有命令對象。

Info Object

對象

一個 AMF 對象至少要有以下三個屬性。

1."level" (字符串):這一消息的等級,"warning"、"status"、"error" 中的某個值;

2."code" (字符串):消息碼,例如 "NetStream.Play.Start";

3."description" (字符串):關於這個消息人類可讀描述。

 服務器只發這三個就可以滿足客戶端的需求

14、video data:type id=9=videodata

音視頻格式以後專門講解以爲設計到H264與AAC還有Thunk 分包

15、audio data:type id=8=audiodata

音視頻格式以後專門講解以爲設計到H264與AAC還有Thunk 分包

 

下一篇講解AMF格式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章