理解RTMP協議——chunk格式

本文梳理了理解RTMP協議的基本概念
訪問 個人博客瞭解更多

RTMP 的 message 與 chunk

message 是 RTMP 中的 M,是消息的單位html

RTMP Message Header
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
    | Message Type| Payload length|  
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
    |       Timestamp             |  
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+  
    |       Stream ID       |  
    +-+-+-+-+-+-+-+-+-+-+-+-+
  • Message Type(1 byte),消息類型很重要,它表明了這個消息是什麼類型,當寫程序的時候須要根據不一樣的消息,作不一樣的處理。
  • Payload length(3 bytes),表示負載的長度(big-endian 格式)
  • Timestamp (4 bytes),時間戳(big-endian 格式),超過最大值後會翻轉
  • Stream ID (3 bytes) ,消息流ID(big-endian 格式),用於區分不一樣流的消息。
  • Message Payload,真實的數據

message 的類型

消息主要分爲三類: 協議控制消息、數據消息、命令消息等shell

  • 協議控制消息服務器

    • Message Type ID = 1~6,主要用於協議內的控制
  • 數據消息網絡

    • Message Type ID = 8 9 18tcp

      • 8: Audio 音頻數據
      • 9: Video 視頻數據
      • 18: Metadata 包括音視頻編碼、視頻寬高等信息。
  • 命令消息 Command Message (20, 17)ide

    • 此類型消息主要有 NetConnection 和 NetStream 兩個類,兩個類分別有多個函數,該消息的調用,可理解爲遠程函數調用。

更多的瞭解見 Adobe’s Real Time Messaging Protocol 的 5.4 章節函數

Chunk —— 網絡中實際發送的內容

rtmp 的 message 會切分爲 n 個 chunk,再經過 tcp 協議傳輸post

爲何 rtmp 基於 tcp 協議,tcp 協議已經有化整爲零的方式, rtmp 還須要將 message 劃分更小的單元 chunk 呢?優化

分析緣由:編碼

  • tcp 協議劃分一個個 tcp 報文,是爲了在網絡傳輸層上保障數據連續性,丟包重發等特性
  • rtmp 劃分 chunk 消息快,是爲了在網絡應用層上實現低延遲的特性,防止大的數據塊(如視頻數據)阻塞小的數據塊(如音頻數據或控制信息)

RTMP 的 chunk 設計思想

在互聯網中傳輸數據時, 消息(Message)會被拆分紅更小的單元, 稱爲消息塊(Chunk)。RTMP Chunk Stream 層級容許在Message stream 層次,將大消息切割成小消息,這樣能夠避免大的低優先級的消息(如視頻消息)阻塞小的高優先級的消息(如音頻消息或控制消息)。

重複強調,RTMP 是設計用來多路複用的特色,傳輸內容有視頻、音頻、控制命令。其中一個很是重要的概念是 multiplexing (複用)

不一樣類型的消息會被分配不一樣的優先級,當網絡傳輸能力受限時,優先級用來控制消息在網絡底層的排隊順序。

好比當客戶端網絡不佳時,流媒體服務器可能會選擇丟棄視頻消息,以保證音頻消息可及時送達客戶端。

Chunk 的大小設置,經過 Message Type = 1 的控制消息聲明

若是 message length 大於 max chunk size,則須要將這個message切分爲多個 chunk 。前面幾個 chunk size 必須是 max size,最後一個就是剩餘的大小。

以上圖爲例,Message大小爲 300 bytes,默認Chunk size 爲 128 bytes,進行拆分紅chunk的過程。

接下來,探尋 chunk 的結構

RTMP Chunk Header
    +-------------+----------------+-------------------+-----------+  
    | Basic header|Chunk Msg Header|Extended Time Stamp|Chunk Data |  
    +-------------+----------------+-------------------+-----------+ 
        1 byte     (0,3,7,11 byte)     (0,4 byte)
設計基於TCP協議的上層協議時,爲了防止粘包問題,通常的方法有:一、使用分隔符; 二、在報文header中聲明長度。
RTMP Chunk Basic Header (1 byte)
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-
    | format | chunk stream id |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-
        2 bits      6 bits

RTMP Chunk Header 的長度不是固定的,由RTMP Chunk Basic Header 前2位二進制決定,有4種類型。chunk stream id 的範圍 3~65599,0~2做爲保留。

  • format = 00,Chunk Header length = 12 bytes,在一個 chunk 流的開始、時間戳返回的時候必須有這種塊,好比:onMetaData, 音視頻流剛開始的絕對時間戳,控制消息
Basic header + Chunk Msg Header
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | format | chunk stream id | timestamp | message length | msg type id | msg stream id |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
        2 bits      6 bits        3 bytes       3 bytes         1 bytes        4 bytes
  • format = 01,Chunk Header length = 8 bytes,對於可變大小消息的chunk流,在第一個消息以後的每一個消息的第一個塊應該使用這個格式
Basic header + Chunk Msg Header
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    | format | chunk stream id | timestamp | message length | msg type id |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      2 bits       6 bits        3 bytes      3 bytes         1 bytes
  • format = 10,Chunk Header length = 4 bytes,對於固定大小消息的chunk流,在第一個消息以後的每一個消息的第一個塊應該使用這個格式
Basic header + Chunk Msg Header
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
    | format | chunk stream id | timestamp |
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
      2 bits       6 bits           3 bytes
  • format = 11,Chunk Header length = 1 bytes,當一個消息被分紅多個塊,除了第一塊之外,全部的塊都應使用這種類型
Basic header + Chunk Msg Header
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-
    | format | chunk stream id | 
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-
      2 bits       6 bits

注意 timestamp 的長度爲 3 bytes,當 timestamp 被設置爲 0x00ffffff,chunk header 會加上 Extended Time Stamp 字段,不然 Extended Time Stamp 不會出現。

  • 由於一個流當中能夠傳輸多個Chunk,那麼多個Chunk怎麼標記同屬於一個 Message 的呢?

    • 是經過Chunk Stream ID 區分的,同一個Chunk Stream ID 必然屬於同一個 Message
    • 由於TCP的有序,因此同一個 Message 中不一樣的 Chunk 會前後抵達。

協議控制消息的chunk

Message type 1~6:

  • 1,Set Chunk Size 設置塊的大小,通知對端用使用新的塊大小,共4 bytes
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |Basic Header|Message Header|Ex Timestamp|Set chunk size  |  
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 2,Abort Message 取消消息,用於通知正在等待接收塊以完成消息的對等端,丟棄一個塊流中已經接收的部分而且取消對該消息的處理,共4 bytes。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |Basic Header|Message Header|Ex Timestamp|Chunk Stream ID |  
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 3,Acknowledgement 確認消息,客戶端或服務端在接收到數量與窗口大小相等的字節後發送確認消息到對方。窗口大小是在沒有接收到接收者發送的確認消息以前發送的字節數的最大值。服務端在創建鏈接以後發送窗口大小。本消息指定序列號。序列號,是到當前時間爲止已經接收到的字節數。共4 bytes。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   |Basic Header|Message Header|Ex Timestamp| Sequence Number|  
   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  • 4, User Control Message 用戶控制消息,客戶端或服務端發送本消息通知對方用戶的控制事件。本消息承載事件類型和事件數據。消息數據的頭兩個字節用於標識事件類型。事件類型以後是事件數據。事件數據字段

是可變長的。

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
    |Basic Header|Message Header|Ex Timestamp| Event Type| Event Data|  
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-++-+-+-+
  • 5,Window Acknowledgement Size 確認窗口大小,客戶端或服務端發送本消息來通知對方發送確認(致謝)消息的窗口大小,共4 bytes.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
    |Basic Header|Message Header|Ex Timestamp| Acknowledgement Window size |     
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • 6,Set Peer Bandwidth 設置對等端帶寬,客戶端或服務端發送本消息更新對等端的輸出帶寬。發送者能夠在限制類型字段(1 bytes)把消息標記爲硬(0),軟(1),或者動態(2)。若是是硬限制對等端必須按提供的帶寬發送數據。若是是軟限制,對等端能夠靈活決定帶寬,發送端能夠限制帶寬?。若是是動態限制,帶寬既能夠是硬限制也能夠是軟限制。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
    |Basic Header|Message Header|Ex Timestamp| Acknowledgement Window size |  
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++  
    |  Limit type  |  
    ++++++++++++++++

音頻消息的chunk

Message type = 8,Audio message, 客戶端或服務端發送本消息用於發送音頻數據。消息類型 8 ,保留爲音頻消息

以 FLV ACC 的 RTMP Audio Chunk 爲例

協議層:

 協議層                封裝層
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    |RTMP Chunk Header | FLV AudioTagHeader | FLV AudioTagBody |     
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

封裝層(FLV):

FLV AudioTagHeader

    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    |SoundFormat | SoundRate | SoundSize | SoundType | AACPacketType |   
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       4 bits       2 bits      1 bit       1 bit        8 bits

視頻消息的chunk

Message type = 9, Video message, 客戶端或服務端使用本消息向對方發送視頻數據。消息類型值 9 ,保留爲視頻消息。

以 FLV H.264/AVC 的 RTMP Video Chunk 爲例

協議層:

 協議層                封裝層
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    |RTMP Chunk Header | FLV VideoTagHeader | FLV VideoTagBody |     
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

封裝層(FLV):

FLV VideoTagHeader

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 
    |Frame Type | CodecID | AVCPacketType | CompositionTime |    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       4 bits      4 bits     1 byte          3 bytes

編碼層:

FLV VideoTagBody 

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    |   Size   | AVCDecoderConfigurationRecord or ( one or more NALUs ) |    
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      4 bytes

NALU: Network Abstract Layer Unit 網絡抽象層單元

總結

  • RTMP 低延遲的特性,來自 多路複用,消息分塊,消息分優先級 的方法

Reference

相關文章
相關標籤/搜索