RTMP協議詳解 rtmp 協議詳解
rtmp 協議詳解
</h1>
<div class="clear"></div>
<div class="postBody">
<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown">
1. handshake
1.1 概述
rtmp 連線從握手開始。它包含三個固定大小的塊。客戶端傳送的三個塊命名為 C0,C1,C2;服務端傳送的三個塊命名為
S0,S1,S2。
握手序列:
- 客戶端通過傳送 C0 和 C1 訊息來啟動握手過程。客戶端必須接收到 S1 訊息,然後傳送 C2 訊息。客戶端必須接收到
S2 訊息,然後傳送其他資料。 - 服務端必須接收到 C0 或者 C1 訊息,然後傳送 S0 和 S1 訊息。服務端必須接收到 C2 訊息,然後傳送其他資料。
握手示意圖
.
+-------------+ +-------------+
| Client | TCP/IP Network | Server |
+-------------+ | +-------------+
| | |
Uninitialized | Uninitialized
| C0 | |
|------------------->| C0 |
| |-------------------->|
| C1 | |
|------------------->| S0 |
| |<--------------------|
| | S1 |
Version sent |<--------------------|
| S0 | |
|<-------------------| |
| S1 | |
|<-------------------| Version sent
| | C1 |
| |-------------------->|
| C2 | |
|------------------->| S2 |
| |<--------------------|
Ack sent | Ack Sent
| S2 | |
|<-------------------| |
| | C2 |
| |-------------------->|
Handshake Done | Handshake Done
| | |
Pictorial Representation of Handshake
[譯]握手示意圖
1.2 complex handshake
1.2.1 C0 和 S0 格式
C0 和 S0 包由一個位元組組成,下面是 C0/S0 包內的欄位:
.
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| version |
+-+-+-+-+-+-+-+-+
C0 and S0 bits
- version(1 byte):RTMP 的版本,一般為 3。
1.2.2 C1 和 S1 格式
C1和S1包含兩部分資料:key和digest,分別為如下:
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| version (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| key (764 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| digest (764 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C1 and S1 bits
key 和 digest 的順序是不確定的,也有可能是:(nginx-rtmp中是如下的順序):
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| version (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| digest (764 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| key (764 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C1 and S1 bits
764 bytes key 結構:
- random-data: (offset) bytes
- key-data: 128 bytes
- random-data: (764 - offset - 128 - 4) bytes
- offset: 4 bytes
764 bytes digest 結構:
- offset: 4 bytes
- random-data: (offset) bytes
- digest-data: 32 bytes
- random-data: (764 - 4 - offset - 32) bytes
1.2.3 C2 和 S2 格式
.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random-data (1504 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| digest-data (32 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C2 and S2 bits
hanshake:S0 + S1 + S2
1.3 simple handshake
1.3.1 C0 和 S0 格式
C0 和 S0 包由一個位元組組成,下面是 C0/S0 包內的欄位:
.
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
| version |
+-+-+-+-+-+-+-+-+
C0 and S0 bits
- version(1 byte):版本。在 C0 包內,這個欄位代表客戶端請求的 RTMP 版本號。在 S0 包內,這個欄位代表服務端選
擇的 RTMP 版本號。當前使用的版本是 3。版本 0-2 用在早期的產品中,如今已經棄用;版本 4-31 被預留用於後續產
品;版本 32-255 (為了區分 RTMP 協議和文字協議,文字協議通常是可以列印字元)不允許使用。如果伺服器無法識別
客戶端的版本號,應該回復版本 3,。客戶端可以選擇降低到版本 3,或者終止握手過程。
1.3.2 C1 和 S1 格式
C1 和 S1 包長度為 1536 位元組,包含以下欄位:
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| zero (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random bytes |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random bytes |
| (cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C1 and S1 bits
- time(4 bytes):本欄位包含一個時間戳,客戶端應該使用此欄位來標識所有流塊的時刻。時間戳取值可以為零或其他
任意值。為了同步多個塊流,客戶端可能希望多個塊流使用相同的時間戳。 - zero(4 bytes):本欄位必須為零。
- random (1528 bytes):本欄位可以包含任意資料。由於握手的雙方需要區分另一端,此欄位填充的資料必須足夠隨機
(以防止與其他握手端混淆)。不過沒有必要為此使用加密資料或動態資料。
1.3.3 C2 和 S2 格式
C2 和 S2 包長度為 1536 位元組,作為 C1 和 S1 的迴應,包含以下欄位:
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| time2 (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random echo |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| random echo |
| (cont) |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
C2 and S2 bits
- time(4 bytes):本欄位必須包含對端傳送的時間戳。
- time2(4 bytes):本欄位必須包含時間戳,取值為接收對端傳送過來的握手包的時刻。
- random(1528 bytes):本欄位必須包含對端傳送過來的隨機資料。握手的雙方可以使用時間 1 和時間 2 欄位來估算
網路連線的頻寬和/或延遲,但是不一定有用。
2. 組塊
2.1 塊格式
.
+--------------+----------------+--------------------+--------------+
| Basic Header | Message Header | Extended Timestamp | Chunk Data |
+--------------+----------------+--------------------+--------------+
| |
|<------------------- Chunk Header ----------------->|
Chunk Format
- 塊的基本頭(1-3位元組):這個欄位包含塊流ID和塊型別。塊型別決定了編碼過的訊息頭的格式。這個欄位是一個變
長欄位,長度取決於塊流ID。 - 訊息頭(0,3,7,11位元組):這個欄位包含被髮送的訊息資訊(無論是全部,還是部分)。欄位長度由塊頭中的
塊型別來決定。 - 擴充套件時間戳(0,4位元組):這個欄位是否存在取決於塊訊息頭中編碼的時間戳。
- 塊資料(可變大小):當前塊的有效資料,上限為配置的最大塊大小。
2.2 Basic Header
包含 chunk stream ID(流通道id)和chunk type(即fmt),chunk stream id 一般被簡寫為CSID,用來唯一標識一個
特定的流通道,chunk type決定了後面Message Header的格式。Basic Header的長度可能是 1,2,或 3 個位元組,
其中 chunk type 的長度是固定的(佔2位,單位是bit),Basic Header 的長度取決於 CSID 的大小,在足夠儲存這兩
個欄位的前提下最好用盡量少的位元組從而減少由於引入Header增加的資料量。
RTMP協議支援使用者自定義 [3,65599] 之間的 CSID,0, 1, 2 由協議保留表示特殊資訊。0 代表 Basic Header 總共要
佔用 2 個位元組,CSID 在 [64,319] 之間; 1 代表佔用 3 個位元組,CSID 在 [64,65599] 之間; 2 代表該 chunk 是控制
資訊和一些命令資訊。
2.2.1 Basic Header:1 byte
.
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|fmt| cs id |
+-+-+-+-+-+-+-+-+
2.2.2 Basic Header: 2 byte , csid == 0
CSID佔14bit,此時協議將於chunk type所在位元組的其他bit都置為0,剩下的一個位元組表示CSID - 64,這樣共有8個bit
來儲存 CSID,8 bit 可以表示 [0,255] 個數,因此這種情況下 CSID 在 [64,319],其中 319 = 255 + 64。
.
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt| 0 | cs id - 64 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.2.3 Basic Header: 3 bytes , csid == 1
CSID佔22bit,此時協議將第一個位元組的[2,8]bit置1,餘下的16個bit表示CSID - 64,這樣共有16個bit來儲存CSID,
16bit可以表示[0,65535]共 65536 個數,因此這種情況下 CSID 在 [64,65599],其中65599=65535+64,需要注意的是,
Basic Header是採用小端儲存的方式,越往後的位元組數量級越高,因此通過3個位元組的每一個bit的值來計算CSID時,
應該是: <第三個位元組的值> * 256 + <第二個位元組的值> + 64.
.
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|fmt| 1 | cs id - 64 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.3 Message Header
包含了要傳送的實際資訊(可能是完整的,也可能是一部分)的描述資訊。Message Header的格式和長度取決於Basic Header
的chunk type,即fmt,共有四種不同的格式。其中第一種格式可以表示其他三種表示的所有資料,但由於其他三種格式是基
於對之前chunk的差量化的表示,因此可以更簡潔地表示相同的資料,實際使用的時候還是應該採用儘量少的位元組表示相同意
義的資料。下面按位元組從多到少的順序分別介紹這四種格式的 Message Header。
Message Header 四種訊息頭格式。
一、Chunk Type(fmt) = 0:11 bytes
.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |message length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| message length (coutinue) |message type id| msg stream id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| msg stream id |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type=0時Message Header佔用11個位元組,其他三種能表示的資料它都能表示,但在chunk stream 的開始第一個chunk和頭資訊
中的時間戳後退(即值與上一個chunk相比減小,通常在回退播放的時候會出現這種情況)的時候必須採用這種格式。
- timestamp(時間戳):佔用3個位元組,因此它最多能表示到16777215=0xFFFFFF=2^24-1,當它
的值超過這個最大值時,這三個位元組都置為1,這樣實際的timestamp會轉存到 Extended
Timestamp 欄位中,接收端在判斷timestamp欄位24個位都為1時就會去Extended Timestamp
中解析實際的時間戳。 - message length(訊息資料長度):佔用3個位元組,表示實際傳送的訊息的資料如音訊幀、視訊
幀等資料的長度,單位是位元組。注意這裡是Message的長度,也就是chunk屬於的Message的總長
度,而不是chunk本身data的長度。 - message type id(訊息的型別id):1個位元組,表示實際傳送的資料的型別,如8代表音訊資料,
9代表視訊資料。 - message stream id(訊息的流id):4個位元組,表示該chunk所在的流的ID,和Basic Header
的CSID一樣,它採用小端儲存方式。
二、Chunk Type(fmt) = 1:7 bytes
.
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp delta |message length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| message length (coutinue) |message type id|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type為1時佔用7個位元組,省去了表示message stream id的4個位元組,表示此chunk和上一次發的 chunk 所在的流相同,如果在
傳送端和對端有一個流連結的時候可以儘量採取這種格式。
- timestamp delta:3 bytes,這裡和type=0時不同,儲存的是和上一個chunk的時間差。類似
上面提到的timestamp,當它的值超過3個位元組所能表示的最大值時,三個位元組都置為1,實際
的時間戳差值就會轉存到Extended Timestamp欄位中,接收端在判斷timestamp delta欄位24
個bit都為1時就會去Extended Timestamp 中解析實際的與上次時間戳的差值。 - 其他欄位與上面的解釋相同.
三、Chunk Type(fmt) = 2:3 bytes
.
0 1 2
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp delta |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
type 為 2 時佔用 3 個位元組,相對於 type = 1 格式又省去了表示訊息長度的3個位元組和表示訊息型別的1個位元組,表示此 chunk
和上一次傳送的 chunk 所在的流、訊息的長度和訊息的型別都相同。餘下的這三個位元組表示 timestamp delta,使用同type=1。
四、Chunk Type(fmt) = 3: 0 byte
type=3時,為0位元組,表示這個chunk的Message Header和上一個是完全相同的。當它跟在type=0的chunk後面時,表示和前一
個 chunk 的時間戳都是相同。什麼時候連時間戳都是相同呢?就是一個 Message 拆分成多個 chunk,這個 chunk 和上
一個 chunk 同屬於一個 Message。而當它跟在 type = 1或 type = 2 的chunk後面時的chunk後面時,表示和前一個 chunk
的時間戳的差是相同的。比如第一個 chunk 的 type = 0,timestamp = 100,第二個 chunk 的 type = 2,
timestamp delta = 20,表示時間戳為 100 + 20 = 120,第三個 chunk 的 type = 3,表示 timestamp delta = 20,
時間戳為 120 + 20 = 140。
2.4 Extended Timestamp(擴充套件時間戳)
在 chunk 中會有時間戳 timestamp 和時間戳差 timestamp delta,並且它們不會同時存在,只有這兩者之一大於3位元組能表示的
最大數值 0xFFFFFF = 16777215 時,才會用這個欄位來表示真正的時間戳,否則這個欄位為 0。擴充套件時間戳佔 4 個位元組,
能表示的最大數值就是 0xFFFFFFFF = 4294967295。當擴充套件時間戳啟用時,timestamp欄位或者timestamp delta要全置為1,
而不是減去時間戳或者時間戳差的值。
2.5 chunk 示例
2.5.1 chunk 示例1
本示例展示了一個音訊訊息流。流中包含有冗餘資訊。
.
+---------+-----------------+-----------------+-----------------+
| |Message Stream ID| Message Type ID | Time | Length |
+---------+-----------------+-----------------+-------+---------+
| Msg # 1 | 12345 | 8 | 1000 | 32 |
+---------+-----------------+-----------------+-------+---------+
| Msg # 2 | 12345 | 8 | 1020 | 32 |
+---------+-----------------+-----------------+-------+---------+
| Msg # 3 | 12345 | 8 | 1040 | 32 |
+---------+-----------------+-----------------+-------+---------+
| Msg # 4 | 12345 | 8 | 1060 | 32 |
+---------+-----------------+-----------------+-------+---------+
Sample audio messages to be made into chunks
- 分析第一個 chunk:
- 首先包含第一個 Message 的 chunk 的 chunk type 為 0,因為它前面沒有可參考的 chunk,timestamp 為 1000,表示時間戳。
- type 為 0 的 header 佔用 11 個位元組,假定 chunk stream id 為 3 < 127,因此 basic header 佔用 1 個位元組;
- 再加上 data 的 32 位元組,因此第一個 chunk 共 44 位元組 = 11 + 1 + 32 個位元組。
- 分析第二個 chunk:
- 第二個 chunk 和第一個 chunk 的 cs id 和 chunk type id,以及 data 的長度都相同,因此採用 型別 2;
- 可知 timestamp delta = 1020 - 1000 = 20;
- 因此第二個 chunk 佔用 36 = 3(message header) + 1(basic header) + 32
- 分析第三個 chunk:
- 第三個 chunk 和第二個 chunk 的 cs id ,chunk type id,以及 data 的長度和時間戳的差值都相同,因此採用 型別 3,省去全部的 Message Header 的資訊;
- 因此佔用 33 = 1 + 32
- 分析第四個 chunk:
- 第四個 chunk 和第三個 chunk 情況相同,也佔用 33 = 1 + 32 個位元組。
最後實際傳送的chunk如下面表格所示,該表格展示了由此音訊流產生的塊資訊。從第 3 條資訊開始,資料傳輸達到最大優
化。每條訊息的頭部只增加了 1 位元組長度。
.
+--------+---------+-----+------------+------- ---+------------+
| | Chunk |Chunk|Header Data |No.of Bytes|Total No.of |
| |Stream ID|Type | | After |Bytes in the|
| | | | |Header |Chunk |
+--------+---------+-----+------------+-----------+------------+
|Chunk#1 | 3 | 0 | delta: 1000| 32 | 44 |
| | | | length: 32,| | |
| | | | type: 8, | | |
| | | | stream ID: | | |
| | | | 12345 (11 | | |
| | | | bytes) | | |
+--------+---------+-----+------------+-----------+------------+
|Chunk#2 | 3 | 2 | 20 (3 | 32 | 36 |
| | | | bytes) | | |
+--------+---------+-----+----+-------+-----------+------------+
|Chunk#3 | 3 | 3 | none (0 | 32 | 33 |
| | | | bytes) | | |
+--------+---------+-----+------------+-----------+------------+
|Chunk#4 | 3 | 3 | none (0 | 32 | 33 |
| | | | bytes) | | |
+--------+---------+-----+------------+-----------+------------+
Format of each of the chunks of audio messages
2.5.2 chunk 示例2
本示例展示了一條長訊息,由於訊息的長度超過了塊的最大長度(128位元組),此訊息在傳輸時將被分割成若干個塊。
.
+-----------+-------------------+-----------------+-----------------+
| | Message Stream ID | Message Type ID | Time | Length |
+-----------+-------------------+-----------------+-----------------+
| Msg # 1 | 12346 | 9 (video) | 1000 | 307 |
+-----------+-------------------+-----------------+-----------------+
Sample Message to be broken to chunks
由表格知 data 的長度 307 > 128,因此這個 Message 要分割成幾個 chunk 傳送:
- 第一個 chunk:type = 0,timestamp = 1000,承擔 128 個位元組的 data,因此共佔用 140 = 11 + 1 + 128 個位元組。
- 第二個 chunk:同樣要傳送 128 位元組,其他欄位(即Message Header 中的幾個欄位)都與第一個相同,因此採用 型別 3,共 129 = 1 + 128 位元組。
- 第三個 chunk:要傳送的 data 的長度為 307 - 128 - 128 = 51 位元組,還是採用 型別 3,共 1 + 51 = 52 位元組。
下面是訊息分割後產生的塊:
.
+-------+------+-----+-------------+-----------+------------+
| |Chunk |Chunk|Header |No. of |Total No. of|
| |Stream| Type|Data |Bytes after| bytes in |
| | ID | | | Header | the chunk |
+-------+------+-----+-------------+-----------+------------+
|Chunk#1| 4 | 0 | delta: 1000 | 128 | 140 |
| | | | length: 307 | | |
| | | | type: 9, | | |
| | | | stream ID: | | |
| | | | 12346 (11 | | |
| | | | bytes) | | |
+-------+------+-----+-------------+-----------+------------+
|Chunk#2| 4 | 3 | none (0 | 128 | 129 |
| | | | bytes) | | |
+-------+------+-----+-------------+-----------+------------+
|Chunk#3| 4 | 3 | none (0 | 51 | 52 |
| | | | bytes) | | |
+-------+------+-----+-------------+-----------+------------+
Format of each of the chunks
第一個塊的頭資料顯示了訊息的長度為 307 位元組。
在這兩個示例中,型別為 3 的塊有兩種使用方式。第一種是說明訊息的繼續。第二種是說明新訊息的頭資訊可以由前面已經存
在的訊息推到出來。
3. 協議控制訊息
RTMP 塊流使用訊息型別 ID 1、2、3、5、6 作為控制訊息。這些訊息包含了必要的 RTMP 塊流協議資訊。
這些協議控制訊息必須使用 0 作為訊息流ID(作為已知的控制流ID),同時使用 2 作為塊流ID。協議控制訊息接收立即生效;
解析時,時間戳欄位被忽略。
3.1 設定塊大小 (1)
協議控制訊息(1),設定塊大小,被用來通知對方新的最大的塊大小。
預設最大的塊大小為 128 位元組,客戶端和伺服器可以使用此訊息來修改預設的塊大小。例如,假設客戶端想要傳送的音訊資料
大小為131 位元組,而塊大小為 128 位元組。在這種情況下,客戶端可以通知伺服器新的塊大小為 131 位元組,然後就可以使用一
個塊來發送完整的音訊資料了。
最大的塊大小至少為 128 位元組,塊至少攜帶 1 個位元組的內容。通訊的每一個方向(例如從客戶端到伺服器)擁有獨立的塊大小
設定。
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0| chunk size (31 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Payload for the ‘Set Chunk Size’ protocol message
- 0:當前位元位必須為零。
- chunk size(31 bits): This field holds the new maximum chunk size, in bytes, which will be used for all of the sender's
subsequent chunks until further notice. Valid sizes are 1 to 2147483647(0x7FFFFFFF) inclusive; however, all sizes
greater than 16777215(0xFFFFFF) are equivalent since no chunk is larger than onemessage, and no message is larger than
16777215 bytes. - 塊大小(31位元):本欄位標識了新的最大塊大小,以位元組為單位,傳送端之後將使用此值作為最大的塊大小。本欄位的
有效值為 1 - 2147483647(0x7FFFFFFF),由於訊息的最大長度為 16777215(0xFFFFFF),而一個塊最多隻能攜帶一條消
息,因此本欄位的實際有效值為 1~16777215(0xFFFFFF)。
send chunk size
3.2 中斷訊息 (2)
協議控制訊息(2),中斷訊息,用來通知通訊的對方,如果正在等待一條訊息的部分塊(已經接收了一部分),那麼可以丟棄
之前已經接收到的塊。通訊的一方將接收到塊流ID作為當前協議訊息的有效資料。應用程式可以傳送此訊息來通知對方,當前
正在傳輸的訊息沒有必要再處理了。
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| chunk stream id (32 bits) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Payload for the ‘Abort Message’ protocol message
- 塊流ID(32位元):本欄位包含了塊流ID,用來標識哪個塊流ID的訊息將被丟棄。
3.3 應答(3)
客戶端和伺服器在接收到與接收視窗大小相等的資料後,必須傳送應答訊息給對方。視窗大小的定義為傳送方在接收到接收方
的任何應答前,可以傳送的最大資料量。本訊息包含了序列號,序列號為截至目前接收到的資料總和,以位元組為單位。
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| sequence number (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Payload for the ‘Acknowledgement’ protocol message
- 序列號(32位元):本欄位包含了截止目前接收到的資料總和,以位元組為單位。
3.4 應答視窗大小(5)
客戶端和伺服器傳送這個訊息來通知對方應答視窗的大小。傳送方在傳送了等於視窗大小的資料之後,等待接收對方的應答消
息(在接收到應答之前停止傳送資料)。接收方必須傳送應答訊息,在會話開始時,或從上一次傳送應答之後接收到了等於窗
口大小的資料。
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgement Window size (4 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Payload for the ‘Window Acknowledgement Size’ protocol message
send ack_size
3.5 設定流頻寬(6)
客戶端和伺服器傳送此訊息來說明對方的出口頻寬限制。接收方以此來限制自己的出口頻寬,即限制未被應答的訊息資料大
小。接收到此訊息的一方,如果視窗大小與上次傳送的不一致,應該回復應答視窗大小的訊息。
.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgement Window size |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Limit Type |
+-+-+-+-+-+-+-+-+
Payload for the ‘Set Peer Bandwidth’ protocol message
限制類型的取值為下面之一:
- 硬限制(0):應該限制出口頻寬為指明的視窗大小。
- 軟限制(1):應該限制出口頻寬為指明的視窗大小,或已經生效的小一點的視窗大小。
- 動態限制(2):如果上一次為硬限制,此訊息被視為硬限制,否則忽略此訊息。
send bandwidth
4. Command Message (17 或 20)
Command Message(命令訊息,Message Type ID = 17 或 20):表示在客戶端和伺服器間傳遞的在對端執行某些操作的命令
訊息,connect 表示連線對端,對端如果同意連線的話就會記錄傳送端資訊並返回連線成功訊息,publish 表示開始向對方
推流,接收端接收到命令後準備好接收對端傳送的流資訊。當資訊使用 AMF0 編碼時,Message Type ID = 20,AMF3 編碼
時 為 17。
伺服器和客戶端之間使用 AMF 編碼的命令訊息互動。 一些命令訊息被用來發送操作指令,比如 connect,createStream,
public,play,pause。另外一些命令訊息被用來通知傳送方請求命令的狀態,比如 onstatus,result 等。一條命令訊息
包括命令對稱、互動 ID、包含相關引數的命令物件。伺服器和客戶端通過在建立的流中遠端呼叫的方式,使用命令訊息來
進行互動。
伺服器傳送給客戶端的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | _result or _error; indicates whether |
| | | the response is result or error. |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID is 1 for connect |
| ID | | responses |
| | | |
+--------------+----------+----------------------------------------+
| Properties | Object | Name-value pairs that describe the |
| | | properties(fmsver etc.) of the |
| | | connection. |
+--------------+----------+----------------------------------------+
| Information | Object | Name-value pairs that describe the |
| | | response from|the server. ’code’, |
| | | ’level’, ’description’ are names of few|
| | | among such information. |
+--------------+----------+----------------------------------------+
命令執行過程中的訊息流如下:
- 客戶端傳送連線命令給伺服器,獲得與伺服器連線的例項。
- 伺服器在接收到連線命令後,傳送應答視窗大小的訊息給客戶端。同時與連線命令中接到的應用建立連線。
- 伺服器傳送設定流頻寬訊息給客戶端。
- 客戶端在接收並處理了設定流頻寬的訊息後,傳送應答視窗大小的訊息給伺服器。
- 伺服器接著傳送開始流的使用者控制訊息給客戶端。
- 伺服器傳送 result 命令訊息給客戶端,通知連線狀態是成功或失敗。命令訊息中包含了事務ID。訊息中還包含了像 FMS
版本之類的屬性,以及級別,編碼,描述,物件編碼等資訊。
+--------------+ +-------------+
| Client | | | Server |
+------+-------+ | +------+------+
| Handshaking done |
| | |
| | |
| | |
| | |
|----------- Command Message(connect) ------->|
| |
|<------- Window Acknowledgement Size --------|
| |
|<----------- Set Peer Bandwidth -------------|
| |
|-------- Window Acknowledgement Size ------->|
| |
|<------ User Control Message(StreamBegin) ---|
| |
|<------------ Command Message ---------------|
| (_result- connect response) |
| |
Message flow in the connect command
4.1 命令型別
客戶端和伺服器通過 AMF 編碼的資料交換命令。傳送者傳送包含命令名稱,事務ID,包含相關引數的命令物件的訊息。例如,
通過連線命令中包含的 APP 引數來告訴伺服器連線的對方是哪個客戶端。接收方處理命令訊息,並使用相同的事務ID應答。
應答字串為 _result 或 _error 或方法名,例如 verifyClient 或 contactExternalServer。事務 ID 標明瞭應答指向的
命令。事務ID相當於 IMAP 協議或其他協議中的標籤。命令字串中的方法名,表明了傳送端想要在接收端執行的方法。
下面的類物件被用來發送各種命令:
- NetConnection:伺服器和客戶端之間進行網路連線的一種高階表示形式。
- NetStream:代表了傳送音訊流,視訊流,或其他相關資料的頻道。當然還有一些像播放,暫停之類的命令,用來控制數
據流。
4.2 網路連線命令
網路連線管理著客戶端和伺服器之間的雙向連線。另外,它也支援非同步遠端命令呼叫。
網路連線允許使用以下的命令:
- 連線 connect
- 呼叫 call
- 停止 close
- 建立流 createStream
4.2.1 connect: 連線
客戶端傳送連線命令給伺服器,來獲取一個和伺服器通訊的例項。客戶端傳送給伺服器的命令結構如下:
.
+----------------+---------+---------------------------------------+
| Field Name | Type | Description |
+--------------- +---------+---------------------------------------+
| Command Name | String | Name of the command. Set to "connect".|
+----------------+---------+---------------------------------------+
| Transaction ID | Number | Always set to 1. |
+----------------+---------+---------------------------------------+
| Command Object | Object | Command information object which has |
| | | the name-value pairs. |
+----------------+---------+---------------------------------------+
| Optional User | Object | Any optional information |
| Arguments | | |
+----------------+---------+---------------------------------------+
下面是連線命令的命令物件裡包含的鍵值對的說明:
.
+-----------+--------+-----------------------------+----------------+
| Property | Type | Description | Example Value |
+-----------+--------+-----------------------------+----------------+
| app | String | The Server application name | testapp |
| | | the client is connected to. | |
+-----------+--------+-----------------------------+----------------+
| flashver | String | Flash Player version. It is | FMSc/1.0 |
| | | the same string as returned | |
| | | by the ApplicationScript | |
| | | getversion () function. | |
+-----------+--------+-----------------------------+----------------+
| swfUrl | String | URL of the source SWF file | file://C:/ |
| | | making the connection. | FlvPlayer.swf |
+-----------+--------+-----------------------------+----------------+
| tcUrl | String | URL of the Server. | rtmp://local |
| | | It has the following format.| host:1935/test |
| | | protocol://servername:port/ | app/instance1 |
| | | appName/appInstance | |
+-----------+--------+-----------------------------+----------------+
| fpad | Boolean| True if proxy is being used.| true or false |
+-----------+--------+-----------------------------+----------------+
|audioCodecs| Number | Indicates what audio codecs | SUPPORT_SND |
| | | the client supports. | _MP3 |
+-----------+--------+-----------------------------+----------------+
|videoCodecs| Number | Indicates what video codecs | SUPPORT_VID |
| | | are supported. | _SORENSON |
+-----------+--------+-----------------------------+----------------+
|videoFunct-| Number | Indicates what special video| SUPPORT_VID |
|ion | | functions are supported. | _CLIENT_SEEK |
+-----------+--------+-----------------------------+----------------+
| pageUrl | String | URL of the web page from | http:// |
| | | where the SWF file was | somehost/ |
| | | loaded. | sample.html |
+-----------+--------+-----------------------------+----------------+
| object | Number | AMF encoding method. | AMF3 |
| Encoding | | | |
+-----------+--------+-----------------------------+----------------+
音訊編碼屬性的可選值:
- 原始 PCM,ADPCM,MP3,NellyMoser(5,8,11,16,22,44kHz),AAC,Speex。
.
+----------------------+----------------------------+--------------+
| Codec Flag | Usage | Value |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_NONE | Raw sound, no compression | 0x0001 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_ADPCM | ADPCM compression | 0x0002 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_MP3 | mp3 compression | 0x0004 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_INTEL | Not used | 0x0008 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_UNUSED | Not used | 0x0010 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_NELLY8 | NellyMoser at 8-kHz | 0x0020 |
| | compression | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_NELLY | NellyMoser compression | 0x0040 |
| | (5, 11, 22, and 44 kHz) | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_G711A | G711A sound compression | 0x0080 |
| | (Flash Media Server only) | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_G711U | G711U sound compression | 0x0100 |
| | (Flash Media Server only) | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_NELLY16 | NellyMouser at 16-kHz | 0x0200 |
| | compression | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_AAC | Advanced audio coding | 0x0400 |
| | (AAC) codec | |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_SPEEX | Speex Audio | 0x0800 |
+----------------------+----------------------------+--------------+
| SUPPORT_SND_ALL | All RTMP-supported audio | 0x0FFF |
| | codecs | |
+----------------------+----------------------------+--------------+
視訊編碼屬性的可選值:
- Sorenson,V1,On2,V2,H264.
.
+----------------------+----------------------------+--------------+
| Codec Flag | Usage | Value |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_UNUSED | Obsolete value | 0x0001 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_JPEG | Obsolete value | 0x0002 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_SORENSON | Sorenson Flash video | 0x0004 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_HOMEBREW | V1 screen sharing | 0x0008 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_VP6 (On2)| On2 video (Flash 8+) | 0x0010 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_VP6ALPHA | On2 video with alpha | 0x0020 |
| (On2 with alpha | channel | |
| channel) | | |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_HOMEBREWV| Screen sharing version 2 | 0x0040 |
| (screensharing v2) | (Flash 8+) | |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_H264 | H264 video | 0x0080 |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_ALL | All RTMP-supported video | 0x00FF |
| | codecs | |
+----------------------+----------------------------+--------------+
視訊函式屬性的可選值:
.
+----------------------+----------------------------+--------------+
| Function Flag | Usage | Value |
+----------------------+----------------------------+--------------+
| SUPPORT_VID_CLIENT | Indicates that the client | 1 |
| _SEEK | can perform frame-accurate | |
| | seeks. | |
+----------------------+----------------------------+--------------+
物件編碼屬性的可選值:
.
+----------------------+----------------------------+--------------+
| Encoding Type | Usage | Value |
+----------------------+----------------------------+--------------+
| AMF0 | AMF0 object encoding | 0 |
| | supported by Flash 6 and | |
| | later | |
+----------------------+----------------------------+--------------+
| AMF3 | AMF3 encoding from | 3 |
| | Flash 9 (AS3) | |
+----------------------+----------------------------+--------------+
示例
C -> S: 伺服器接收客戶端 connect 命令訊息
S -> C: 伺服器響應客戶端 connect 成功訊息
4.2.2 call: 呼叫
網路連線物件中包含的 call 方法,會在接收端執行遠端過程呼叫(RPC)。被呼叫的 RPC 方法名作為 call 方法的引數傳輸。
從傳送端到接收端的命令結構如下:
.
+--------------+----------+----------------------------------------+
|Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Procedure | String | Name of the remote procedure that is |
| Name | | called. |
+--------------+----------+----------------------------------------+
| Transaction | Number | If a response is expected we give a |
| | | transaction Id. Else we pass a value of|
| ID | | 0 |
+--------------+----------+----------------------------------------+
| Command | Object | If there exists any command info this |
| Object | | is set, else this is set to null type. |
+--------------+----------+----------------------------------------+
| Optional | Object | Any optional arguments to be provided |
| Arguments | | |
+--------------+----------+----------------------------------------+
應答的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command. |
| | | |
+--------------+----------+----------------------------------------+
| Transaction | Number | ID of the command, to which the |
| ID | | response belongs.
+--------------+----------+----------------------------------------+
| Command | Object | If there exists any command info this |
| Object | | is set, else this is set to null type. |
+--------------+----------+----------------------------------------+
| Response | Object | Response from the method that was |
| | | called. |
+------------------------------------------------------------------+
4.2.3 createStream: 建立流
客戶端通過傳送此訊息給伺服器來建立一個用於訊息互動的邏輯通道。音訊,視訊,和元資料都是通過 createStream 命令建立
的流通道釋出出去的。
NetConnection 是預設的互動通道,流 ID 為0. 協議和一部分命令訊息,包含 createStream,都是使用預設的互動通道釋出
的。
從客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command. Set to |
| | | "createStream". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID of the command. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Object | If there exists any command info this |
| Object | | is set, else this is set to null type. |
+--------------+----------+----------------------------------------+
從伺服器傳送給客戶端的命令結構:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | _result or _error; indicates whether |
| | | the response is result or error. |
+--------------+----------+----------------------------------------+
| Transaction | Number | ID of the command that response belongs|
| ID | | to. |
+--------------+----------+----------------------------------------+
| Command | Object | If there exists any command info this |
| Object | | is set, else this is set to null type. |
+--------------+----------+----------------------------------------+
| Stream | Number | The return value is either a stream ID |
| ID | | or an error information object. |
+--------------+----------+----------------------------------------+
示例
C -> S: 伺服器接收客戶端 createStream 命令訊息
C -> S: 伺服器響應客戶端 createStream 成功訊息
4.3 網路流命令
網路流定義了通過網路連線把音訊,視訊和資料訊息流在客戶端和伺服器之間進行交換的通道。一個網路連線物件可以有多個
網路流,進而支援多個數據流。
客戶端可以通過網路流傳送到伺服器的命令如下:
- 播放play
- 播放2 play2
- 刪除流 deleteStream
- 關閉流 closeStream
- 接收音訊 receiveAudio
- 接收視訊 receiveVideo
- 釋出 publish
- 定位 seek
- 暫停 pause
伺服器通過傳送 onStatus 命令給客戶端來通知網路流狀態的更新。
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | The command name "onStatus". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | There is no command object for |
| Object | | onStatus messages. |
+--------------+----------+----------------------------------------+
| Info Object | Object | An AMF object having at least the |
| | | following three properties: "level" |
| | | (String): the level for this message, |
| | | one of "warning", "status", or "error";|
| | | "code" (String): the message code, for |
| | | example "NetStream.Play.Start"; and |
| | | "description" (String): a human- |
| | | readable description of the message. |
| | | The Info object MAY contain other |
| | | properties as appropriate to the code. |
+--------------+----------+----------------------------------------+
Format of NetStream status message commands.
4.3.1 play: 播放
客戶端傳送此命令來通知伺服器開始播放流。多次使用此命令可以建立一個播放列表。如果想要建立一個動態播放列表來在不
同的直播或點播流之間切換,可以通過多次呼叫播放命令,同時將 Reset 欄位設定為 false。相反,如果想要立即播放指定
的流,先清理掉之前的播放佇列,再呼叫播放命令,同時將 Reset 欄位設定為 true。
從客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+-----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+-----------------------------------------+
| Command Name | String | Name of the command. Set to "play". |
+--------------+----------+-----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+-----------------------------------------+
| Command | Null | Command information does not exist. |
| Object | | Set to null type. |
+--------------+----------+-----------------------------------------+
| Stream Name | String | Name of the stream to play. |
| | | To play video (FLV) files, specify the |
| | | name of the stream without a file |
| | | extension (for example, "sample"). To |
| | | play back MP3 or ID3 tags, you must |
| | | precede the stream name with mp3: |
| | | (for example, "mp3:sample". To play |
| | | H.264/AAC files, you must precede the |
| | | stream name with mp4: and specify the |
| | | file extension. For example, to play the|
| | | file sample.m4v,specify "mp4:sample.m4v"|
| | | |
+--------------+----------+-----------------------------------------+
| Start | Number | An optional parameter that specifies |
| | | the start time in seconds. The default |
| | | value is -2, which means the subscriber |
| | | first tries to play the live stream |
| | | specified in the Stream Name field. If a|
| | | live stream of that name is not found,it|
| | | plays the recorded stream of the same |
| | | name. If there is no recorded stream |
| | | with that name, the subscriber waits for|
| | | a new live stream with that name and |
| | | plays it when available. If you pass -1 |
| | | in the Start field, only the live stream|
| | | specified in the Stream Name field is |
| | | played. If you pass 0 or a positive |
| | | number in the Start field, a recorded |
| | | stream specified in the Stream Name |
| | | field is played beginning from the time |
| | | specified in the Start field. If no |
| | | recorded stream is found, the next item |
| | | in the playlist is played. |
+--------------+----------+-----------------------------------------+
| Duration | Number | An optional parameter that specifies the|
| | | duration of playback in seconds. The |
| | | default value is -1. The -1 value means |
| | | a live stream is played until it is no |
| | | longer available or a recorded stream is|
| | | played until it ends. If you pass 0, it |
| | | plays the single frame since the time |
| | | specified in the Start field from the |
| | | beginning of a recorded stream. It is |
| | | assumed that the value specified in |
| | | the Start field is equal to or greater |
| | | than 0. If you pass a positive number, |
| | | it plays a live stream for |
| | | the time period specified in the |
| | | Duration field. After that it becomes |
| | | available or plays a recorded stream |
| | | for the time specified in the Duration |
| | | field. (If a stream ends before the |
| | | time specified in the Duration field, |
| | | playback ends when the stream ends.) |
| | | If you pass a negative number other |
| | | than -1 in the Duration field, it |
| | | interprets the value as if it were -1. |
+--------------+----------+-----------------------------------------+
| Reset | Boolean | An optional Boolean value or number |
| | | that specifies whether to flush any |
| | | previous playlist. |
+--------------+----------+-----------------------------------------+
play 播放命令執行流程:
.
+-------------+ +----------+
| Play Client | | | Server |
+------+------+ | +-----+----+
| Handshaking and Application |
| connect done |
| | |
| | |
| | |
| | |
---+---- |------Command Message(createStream) ----->|
Create| | |
Stream| | |
---+---- |<---------- Command Message --------------|
| (_result- createStream response) |
| |
---+---- |------ Command Message (play) ----------->|
| | |
| |<------------ SetChunkSize --------------|
| | |
| |<---- User Control (StreamIsRecorded) ----|
Play | | |
| |<---- User Control (StreamBegin) ---------|
| | |
| |<--Command Message(onStatus-play reset) --|
| | |
| |<--Command Message(onStatus-play start) --|
| | |
| |<-------------Audio Message---------------|
| | |
| |<-------------Video Message---------------|
| | | |
|
Keep receiving audio and video stream till finishes
Message flow in the play command
命令執行過程中的訊息流如下:
- 當客戶端接收到伺服器返回的 createStream 成功的訊息時,開始傳送播放命令。
- 伺服器接收到播放命令後,傳送設定塊大小的訊息。
- 伺服器傳送一條使用者控制訊息,訊息內包含了 StreamlsRecorded 事件和流ID。事件型別位於訊息的前 2 個位元組,流 ID
位於訊息的最後 4 個位元組。 - 伺服器傳送一條使用者控制訊息,訊息內包含了 StreamBegin 事件,用於通知客戶端開始播放流。
- 如果客戶端已經成功傳送了播放命令,那麼伺服器傳送兩條 onStatus 命令給客戶端,命令的內容為 NetStream.Play.Start
和 NetStream.Play.Reset。伺服器只有在客戶端傳送了設定有重置標籤的播放命令後,才能傳送 NetStream.Play.Reset
命令。如果伺服器找不到客戶端請求播放的流,那麼傳送 NetStream.Play.StreamNotFound 命令給客戶端。 - 之後,伺服器傳送音訊和視訊資料給客戶端。
4.3.2 play2: 播放2
與播放命令的不同之處在於,播放 2 命令可以在不修改播放內容時間線的前提下切換到一個不同位元速率的流。伺服器包含了多個
不同位元速率的流檔案用於支援客戶端的播放 2 請求。
從客戶端傳送給伺服器的命令結構如下:
.
The command structure from the client to the server is as follows:
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to "play2". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | Command information does not exist. |
| Object | | Set to null type. |
+--------------+----------+----------------------------------------+
| Parameters | Object | An AMF encoded object whose properties |
| | | are the public properties described |
| | | for the flash.net.NetStreamPlayOptions |
| | | ActionScript object. |
+--------------+----------+----------------------------------------+
有關 NetStreamPlayOptions 物件的公開屬性的說明詳見 AS3 語言的文件。
此命令的訊息流如下所示:
.
+--------------+ +-------------+
| Play2 Client | | | Server |
+--------+-----+ | +------+------+
| Handshaking and Application |
| connect done |
| | |
| | |
| | |
| | |
---+---- |---- Command Message(createStream) --->|
Create | | |
Stream | | |
---+---- |<---- Command Message (_result) -------|
| |
---+---- |------ Command Message (play) -------->|
| | |
| |<------------ SetChunkSize ------------|
| | |
| |<--- UserControl (StreamIsRecorded)----|
Play | | |
| |<------- UserControl (StreamBegin)-----|
| | |
| |<--Command Message(onStatus-playstart)-|
| | |
| |<---------- Audio Message -------------|
| | |
| |<---------- Video Message -------------|
| | |
| |
---+---- |-------- Command Message(play2) ------>|
| | |
| |<------- Audio Message (new rate) -----|
Play2 | | |
| |<------- Video Message (new rate) -----|
| | | |
| | | |
| Keep receiving audio and video stream till finishes
|
Message flow in the play2 command
4.3.3 deleteStream: 刪除流
如果需要銷燬網路流物件,可以通過網路流傳送刪除流訊息給伺服器。
客戶端傳送給伺服器的命令結構如下:
.
The command structure from the client to the server is as follows:
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to |
| | | "deleteStream". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | Command information object does not |
| Object | | exist. Set to null type. |
+--------------+----------+----------------------------------------+
| Stream ID | Number | The ID of the stream that is destroyed |
| | | on the server. |
+--------------+----------+----------------------------------------+
伺服器接收到此訊息後,不做任何回覆。
4.3.4 receiveAudio: 接收音訊
網路流傳送此訊息通知伺服器,是否要傳送音訊資料給客戶端。
.
The command structure from the client to the server is as follows:
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to |
| | | "receiveAudio". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | Command information object does not |
| Object | | exist. Set to null type. |
+--------------+----------+----------------------------------------+
| Bool Flag | Boolean | true or false to indicate whether to |
| | | receive audio or not. |
+--------------+----------+----------------------------------------+
如果伺服器接收到帶有 fasle 標籤的訊息後,不做任何回覆。如果接收到帶有 true 標籤的訊息,伺服器回覆帶有
NetStream.Seek.Notify 和 NetStream.Play.Start 的訊息給客戶端。
4.3.5 receiveVideo: 接收視訊
網路流傳送此訊息通知伺服器,是否要傳送視訊資料給客戶端。
客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to |
| | | "receiveVideo". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | Command information object does not |
| Object | | exist. Set to null type. |
+--------------+----------+----------------------------------------+
| Bool Flag | Boolean | true or false to indicate whether to |
| | | receive video or not. |
+--------------+----------+----------------------------------------+
如果伺服器接收到帶有 false 標籤的訊息後,不做任何回覆。如果接收到帶有 true 標籤的訊息,伺服器回覆帶有
NetStream.Seek.Notify 和 NetStream.Play.Start 的訊息給客戶端。
4.3.6 publish: 釋出
客戶端傳送此訊息,用來發佈一個有名字的流到伺服器。其他客戶端可以使用此流名來播放流,接收發布的音訊,視訊,
以及其他資料訊息。
客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to "publish". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | Command information object does not |
| Object | | exist. Set to null type. |
+--------------+----------+----------------------------------------+
| Publishing | String | Name with which the stream is |
| Name | | published. |
+--------------+----------+----------------------------------------+
| Publishing | String | Type of publishing. Set to "live", |
| Type | | "record", or "append". |
| | | record: The stream is published and the|
| | | data is recorded to a new file.The file|
| | | is stored on the server in a |
| | | subdirectory within the directory that |
| | | contains the server application. If the|
| | | file already exists, it is overwritten.|
| | | append: The stream is published and the|
| | | data is appended to a file. If no file |
| | | is found, it is created. |
| | | live: Live data is published without |
| | | recording it in a file. |
+--------------+----------+----------------------------------------+
伺服器接收到此訊息後,回覆 onStatus 命令來標記釋出的開始。
示例1:釋出錄製的視訊
此示例闡述了釋出者如果釋出視訊流到伺服器。其他客戶端可以訂閱並播放此視訊流。
.
+--------------------+ +-----------+
| Publisher Client | | | Server |
+----------+---------+ | +-----+-----+
| Handshaking Done |
| | |
| | |
---+---- |----- Command Message(connect) ----->|
| | |
| |<----- Window Acknowledge Size ------|
Connect | | |
| |<-------Set Peer BandWidth ----------|
| | |
| |------ Window Acknowledge Size ----->|
| | |
| |<------User Control(StreamBegin)-----|
| | |
---+---- |<---------Command Message -----------|
| (_result- connect response) |
| |
---+---- |--- Command Message(createStream)--->|
Create | | |
Stream | | |
---+---- |<------- Command Message ------------|
| (_result- createStream response) |
| |
---+---- |---- Command Message(publish) ------>|
| | |
| |<------User Control(StreamBegin)-----|
| | |
| |-----Data Message (Metadata)-------->|
| | |
Publishing| |------------ Audio Data ------------>|
Content | | |
| |------------ SetChunkSize ---------->|
| | |
| |<----------Command Message ----------|
| | (_result- publish result) |
| | |
| |------------- Video Data ----------->|
| | | |
| | | |
| Until the stream is complete |
| | |
Message flow in publishing a video stream
示例2:從錄製的流釋出元資料
本示例展示了釋出元資料的訊息交換過程。
.
+------------------+ +---------+
| Publisher Client | | | FMS |
+---------+--------+ | +----+----+
| Handshaking and Application |
| connect done |
| | |
| | |
---+--- |---Command Messsage(createStream) -->|
Create | | |
Stream | | |
---+--- |<---------Command Message------------|
| (_result - command response) |
| |
---+--- |---- Command Message(publish) ------>|
Publishing | | |
metadata | |<------ UserControl(StreamBegin)-----|
from file | | |
| |-----Data Message (Metadata) ------->|
| |
Publishing metadata
4.3.7 seek: 定位
客戶端傳送此訊息來定位多媒體檔案或播放列表的偏移(以毫秒為單位)。
客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to "seek". |
+--------------+----------+----------------------------------------+
| Transaction | Number | Transaction ID set to 0. |
| ID | | |
+--------------+----------+----------------------------------------+
| Command | Null | There is no command information object |
| Object | | for this command. Set to null type. |
+--------------+----------+----------------------------------------+
| milliSeconds | Number | Number of milliseconds to seek into |
| | | the playlist. |
+--------------+----------+----------------------------------------+
當定位完成後,伺服器回覆 NetStream.Seek.Notify 狀態訊息給客戶端。如果定位失敗,將回復 _error 訊息。
4.3.8 pause: 暫停
客戶端傳送此訊息來通知伺服器暫停或開始播放。
客戶端傳送給伺服器的命令結構如下:
.
+--------------+----------+----------------------------------------+
| Field Name | Type | Description |
+--------------+----------+----------------------------------------+
| Command Name | String | Name of the command, set to "pause". |
+--------------+----------+----------------------------------------+
| Transaction | Number | There is no transaction ID for this |
| ID | | command. Set to 0. |
+--------------+----------+----------------------------------------+
| Command | Null | Command information object does not |
| Object | | exist. Set to null type. |
+--------------+----------+----------------------------------------+
|Pause/Unpause | Boolean | true or false, to indicate pausing or |
| Flag | | resuming play |
+--------------+----------+----------------------------------------+
| milliSeconds | Number | Number of milliseconds at which the |
| | | the stream is paused or play resumed. |
| | | This is the current stream time at the |
| | | Client when stream was paused. When the|
| | | playback is resumed, the server will |
| | | only send messages with timestamps |
| | | greater than this value. |
+--------------+----------+----------------------------------------+
當流暫停成功,伺服器傳送 NetStream.Pause.Notify 狀態訊息給客戶端,如果流未暫停,伺服器傳送
NetStream.Unpause.Notify 狀態訊息給客戶端。如果暫停失敗,則傳送 _error 訊息。
5. Data Message ( 15 或 18)
Data Message(資料訊息,Message Type ID = 15 或 18):傳遞一些元資料(Metadata,比如視訊名,解析度等等)或者用
戶自定義的一些訊息。當資訊使用 AMF0 編碼時,Message Type ID = 18,AMF3 則為15.
元資料包含了(音視訊)資料的細節資訊,像流的建立時間,時間點,主題等等.
6. Shared Object Message (16 或 19)
Shared Object Message(共享訊息,Message Type ID = 16 或 19):表示一個 Flash 型別的物件,由鍵值對的集合組成,用
於多客戶端,多例項時使用。AMF0 時 Message Type ID 為 19,AMF3 為 16。每個訊息可以包含多個事件。
共享訊息格式:
.
+------+------+-------+-----+-----+------+-----+ +-----+------+-----+
|Header|Shared|Current|Flags|Event|Event |Event|.|Event|Event |Event|
| |Object|Version| |Type |data |data |.|Type |data |data |
| |Name | | | |length| |.| |length| |
+------+------+-------+-----+-----+------+-----+ +-----+------+-----+
| |
|<- - - - - - - - - - - - - - - - - - - - - - - - - - - - - >|
| AMF Shared Object Message body |
The shared object message format
下面是共享訊息支援的事件型別:
.
+---------------+--------------------------------------------------+
| Event | Description |
+---------------+--------------------------------------------------+
| Use(=1) | The client sends this event to inform the server |
| | about the creation of a named shared object. |
+---------------+--------------------------------------------------+
| Release(=2) | The client sends this event to the server when |
| | the shared object is deleted on the client side. |
+---------------+--------------------------------------------------+
| Request Change| The client sends this event to request that the |
| (=3) | change the value associated with a named |
| | parameter of the shared object. |
+---------------+--------------------------------------------------+
| Change (=4) | The server sends this event to notify all |
| | clients, except the client originating the |
| | request, of a change in the value of a named |
| | parameter. |
+---------------+--------------------------------------------------+
| Success (=5) | The server sends this event to the requesting |
| | client in response to RequestChange event if the |
| | request is accepted. |
+---------------+--------------------------------------------------+
| SendMessage | The client sends this event to the server to |
| (=6) | broadcast a message. On receiving this event, |
| | the server broadcasts a message to all the |
| | clients, including the sender. |
+---------------+--------------------------------------------------+
| Status (=7) | The server sends this event to notify clients |
| | about error conditions. |
+---------------+--------------------------------------------------+
| Clear (=8) | The server sends this event to the client to |
| | clear a shared object. The server also sends |
| | this event in response to Use event that the |
| | client sends on connect. |
+---------------+--------------------------------------------------+
| Remove (=9) | The server sends this event to have the client |
| | delete a slot. |
+---------------+--------------------------------------------------+
| Request Remove| The client sends this event to have the client |
| (=10) | delete a slot. |
+---------------+--------------------------------------------------+
| Use Success | The server sends this event to the client on a |
| (=11) | successful connection. |
+---------------+--------------------------------------------------+
示例:廣播共享物件訊息
此示例闡述了流建立過程中的訊息交換,和共享物件的變換過程。同時還展示了共享物件訊息廣播的處理過程。
.
+----------+ +----------+
| Client | | | Server |
+-----+----+ | +-----+----+
| Handshaking and Application |
| connect done |
| | |
| | |
| | |
| | |
Create and ---+---- |---- Shared Object Event(Use)---->|
connect | | |
Shared Object | | |
---+---- |<---- Shared Object Event---------|
| (UseSuccess,Clear) |
| |
---+---- |------ Shared Object Event ------>|
Shared object | | (RequestChange) |
Set Property | | |
---+---- |<------ Shared Object Event ------|
| (Success) |
| |
---+---- |------- Shared Object Event ----->|
Shared object| | (SendMessage) |
Message | | |
Broadcast ---+---- |<------- Shared Object Event -----|
| (SendMessage) |
| |
| |
Shared object message broadcast
7. Audio Message (8)
Audio Message(音訊資訊,Message Type ID = 8):音訊資料
8. Video Message (9)
Video Message(視訊資訊,Message Type ID = 9):視訊資料
9. Aggregate Message (22)
Aggregate Message(聚集資訊,Message Type ID = 22):多個 RTMP 子訊息的集合。
集合訊息由訊息頭和訊息內容組成。
訊息內容由子訊息組成,子訊息由訊息頭,訊息資料,回放指標組成。
.
+---------+-------------------------+
| Header | Aggregate Message body |
+---------+-------------------------+
The Aggregate Message format
+--------+-------+---------+--------+-------+---------+ - - - -
|Header 0|Message|Back |Header 1|Message|Back |
| |Data 0 |Pointer 0| |Data 1 |Pointer 1|
+--------+-------+---------+--------+-------+---------+ - - - -
The Aggregate Message body format
集合訊息的訊息流 ID 覆蓋此訊息內的子訊息流的ID。
集合訊息和第一個子訊息的時間戳之間的偏移量,用來將子訊息的時間戳處理為流的時間刻度。每個子訊息的時間戳可以通過
新增偏移量來處理為正常的流時間。第一個子訊息的時間戳應該和集合訊息的時間戳相同,因此偏移量應該為零。
方向指標包含了以前的訊息(包含頭資訊)的大小。集合訊息包含此欄位,一是為了適配 FLV 檔案格式,二是為了回放定位。
使用集合訊息有如下幾種優勢:
- 塊流在一個塊內至多可以攜帶一條完整的訊息。使用集合訊息之後,不僅可以增加塊大小,同時還減少了傳送的塊數
量; - 集合訊息的子訊息可以連續的儲存在記憶體中。當系統呼叫網路傳送資料時更高效。
10. User Control Message Events (4)
User Control Message Events(使用者控制訊息,Message Type ID = 4):告知對方執行該資訊中包含的使用者控制事件,比如
Stream Begin 事件告知對方流資訊開始傳輸。和前面提到的協議控制資訊(Protocol Control Message)不同,使用者控制訊息
是在 RTMP 協議層的,而不是在 RTMP chunk 流協議層,這個很容易弄混。該資訊在 chunk 流中傳送時,Message Stream ID
= 0,Chunk Strean id = 2,Message type id = 4.
使用者控制訊息應該使用 0 作為訊息流 ID,當通過 RTMP 塊流傳送此訊息時,塊流 ID 為 2. RTMP 流中的使用者控制訊息在接收
時立即生效,訊息中的時間戳被忽略。
客戶端或伺服器傳送此訊息用來通知對方使用者控制事件。此訊息包含事件型別和事件資料。
.
+------------------------------+------------------------
| Event Type (16 bits) | Event Data
+------------------------------+-------------------------
Payload for the ‘User Control’ protocol message
使用者控制訊息的前 2 個位元組資料用來標識事件型別。事件型別後面是事件資料。事件資料欄位是可變的。由於此訊息是通過
RTMP 塊流層傳送的,塊大小的最大值應該滿足在一個塊裡包含此訊息。
使用者控制事件支援如下型別:
+---------------+--------------------------------------------------+
| Event | Description |
+---------------+--------------------------------------------------+
|Stream Begin | The server sends this event to notify the client |
| (=0) | that a stream has become functional and can be |
| | used for communication. By default, this event |
| | is sent on ID 0 after the application connect |
| | command is successfully received from the |
| | client. The event data is 4-byte and represents |
| | the stream ID of the stream that became |
| | functional. |
+---------------+--------------------------------------------------+
| Stream EOF | The server sends this event to notify the client |
| (=1) | that the playback of data is over as requested |
| | on this stream. No more data is sent without |
| | issuing additional commands. The client discards |
| | the messages received for the stream. The |
| | 4 bytes of event data represent the ID of the |
| | stream on which playback has ended. |
+---------------+--------------------------------------------------+
| StreamDry | The server sends this event to notify the client |
| (=2) | that there is no more data on the stream. If the |
| | server does not detect any message for a time |
| | period, it can notify the subscribed clients |
| | that the stream is dry. The 4 bytes of event |
| | data represent the stream ID of the dry stream. |
+---------------+--------------------------------------------------+
| SetBuffer | The client sends this event to inform the server |
| Length (=3) | of the buffer size (in milliseconds) that is |
| | used to buffer any data coming over a stream. |
| | This event is sent before the server starts |
| | processing the stream. The first 4 bytes of the |
| | event data represent the stream ID and the next |
| | 4 bytes represent the buffer length, in |
| | milliseconds. |
+---------------+--------------------------------------------------+
| StreamIs | The server sends this event to notify the client |
| Recorded (=4) | that the stream is a recorded stream. The |
| | 4 bytes event data represent the stream ID of |
| | the recorded stream. |
+---------------+--------------------------------------------------+
| PingRequest | The server sends this event to test whether the |
| (=6) | client is reachable. Event data is a 4-byte |
| | timestamp, representing the local server time |
| | when the server dispatched the command. The |
| | client responds with PingResponse on receiving |
| | MsgPingRequest. |
+---------------+--------------------------------------------------+
| PingResponse | The client sends this event to the server in |
| (=7) | response to the ping request. The event data is |
| | a 4-byte timestamp, which was received with the |
| | PingRequest request. |
+---------------+--------------------------------------------------+
10.1 Stream Begin
10.2 record
10.3 Stream EOF
分類: RTMP 標籤: rtmp<div id="blog_post_info">
好文要頂
關注我
收藏該文
季末的天堂關注 - 1
粉絲 - 46 +加關注 4 0
<div class="clear"></div>
<div id="post_next_prev">
<a href="https://www.cnblogs.com/jimodetiantang/p/8987867.html" class="p_n_p_prefix">« </a> 上一篇: <a href="https://www.cnblogs.com/jimodetiantang/p/8987867.html" data-featured-image="" title="釋出於 2018-05-03 22:24">Nginx-rtmp之 ngx_rtmp_send.c 檔案分析</a>
<br>
<a href="https://www.cnblogs.com/jimodetiantang/p/8994061.html" class="p_n_p_prefix">» </a> 下一篇: <a href="https://www.cnblogs.com/jimodetiantang/p/8994061.html" data-featured-image="" title="釋出於 2018-05-08 21:10">Nginx-rtmp直播之業務流程分析</a>
posted @
2018-05-04 11:36
季末的天堂
閱讀(19079)
評論(0)
編輯
收藏
舉報