1. 程式人生 > >RTSP/RTP 媒體傳輸和控制協議

RTSP/RTP 媒體傳輸和控制協議

1 前言

本文件主要描述了 NewStream Vision 系統中前端視訊伺服器(DVR, 網路攝像機), 中心轉發伺服器以及客戶端之間的多媒體通訊以及控制協議.

本協議主要基於標準的 IETE 的 RTSP/RTP 以及相關協議, 並針對具體應用定義了部分擴充套件.

本協議只是當前實現的總結和整理, 具體的協議細節以實際實現為準

2 定義

RTSP
實現流協議
SDP
會話描述協議
RTP
實時傳輸協議
H.264
H.264 視訊編碼標準

3 RTSP 命令

3.1 Request 語法

語法:

RTSP 的語法和 HTTP 的語法基本相同, 具體如下。

COMMAND rtsp_URL RTSP/1.0<CRLF>
Headerfield1: val1<CRLF>
Headerfield2: val2<CRLF>
...
<CRLF>
[Body]

RTSP 訊息行之間用回車換行 (CRLF) 分隔. 一個空行表示訊息頭部分的結束。

3.1.1 RTSP 方法

COMMAND 表示 RTSP 命令名稱, 是 DESCRIBE, SETUP, OPTIONS, PLAY, PAUSE, TEARDOWN 或 SET_PARAMETER 等的任意一個.

3.1.2 RTSP URL

完整語法如下:

rtsp_URL  =   ( "rtsp:" | "rtspu:" )
                 "//" host [ ":" port ] [ abs_path ]
   host   =   (A legal Internet host domain name of IP address
                 (in dotted decimal form), as defined by Section 2.1
				of RFC 1123 \cite{rfc1123})
   port   =   *DIGIT

如: rtsp://<servername>/live.mp4[?<param>=<value>[&<param>=<value>...]]

<servername> 表示產品的主機名稱或者 IP 地址.

3.1.3 RTSP 版本

格式和 HTTP 協議類似, 且 RTSP 版本總是為 "RTSP/1.0"

3.1.4 RTSP 頭欄位

下面是所有命令都接受的頭欄位型別,一些命令接受或者必須用到一些附加的特別的頭欄位。

頭欄位 描述
Authorization 客戶端的認證資訊.
CSeq 請求序列號.
Session 會話 ID (返回自服務端的 SETUP 應答).
Content-Length 內容的長度.
Content-Type 內容的媒體型別.
User-Agent 關於建立這個請求的客戶端的資訊.
Require 查詢是否支援指定的選項,不支援的選項會在 Unsupported 頭中列出.

3.2 Response 語法

語法:

RTSP/1.0 <Status Code> <Reason Phrase> <CRLF>
Headerfield3: val3<CRLF>
Headerfield4: val4<CRLF>
...
<CRLF>
[Body]

應答的第一行包含了表示請求是否成功或者失敗的狀態碼和原因短語. 在 RFC 2326 有對狀態碼的詳細描述.

標準的 RTSP 應答狀態碼和原因短語:

”100” ; Continue (all 100 range)
 “200” ; OK
 ”201” ; Created
 ”250” ; Low on Storage Space
 ”300” ; Multiple Choices
 ”301” ; Moved Permanently
 ”302” ; Moved Temporarily
 ”303” ; See Other
 ”304” ; Not Modified
 ”305” ; Use Proxy
 ”350” ; Going Away
 ”351” ; Load Balancing
 ”400” ; Bad Request
 ”401” ; Unauthorized
 ”402” ; Payment Required
 ”403” ; Forbidden
 ”404” ; Not Found
 ”405” ; Method Not Allowed
 ”406” ; Not Acceptable
 ”407” ; Proxy Authentication Required
 ”408” ; Request Time-out
 ”410” ; Gone
 ”411” ; Length Required
 ”412” ; Precondition Failed
 ”413” ; Request Entity Too Large
 ”414” ; Request-URI Too Large
 ”415” ; Unsupported Media Type
 ”451” ; Parameter Not Understood
 ”452” ; reserved
 ”453” ; Not Enough Bandwidth
 ”454” ; Session Not Found
 ”455” ; Method Not Valid in This State
 ”456” ; Header Field Not Valid for Resource
 ”457” ; Invalid Range
 ”458” ; Parameter Is Read-Only
 ”459” ; Aggregate operation not allowed
 ”460” ; Only aggregate operation allowed
 ”461” ; Unsupported transport
 ”462” ; Destination unreachable
 ”500” ; Internal Server Error
 ”501” ; Not Implemented
 ”502” ; Bad Gateway
 ”503” ; Service Unavailable
 ”504” ; Gateway Time-out
 ”505” ; RTSP Version not supported
 ”551” ; Option not supported

下面的頭欄位可以在所有的 RTSP 應答訊息中包含。

頭欄位 描述
CSeq 應答序列號 (和請求序列匹配).
Session 會話 ID.
WWW-Authenticate 客戶端的認證資訊.
Date 應答的日期和時間.
Unsupported 服務端不支援的特性和功能.

3.3 RTSP DESCRIBE

DESCRIBE 命令用於請求指定的媒體流的 SDP 描述資訊。關於 SDP ( Session Description Protocol,會話描述協議) 請參考 RFC 2327.

DESCRIBE 請求訊息接受如下附加的頭欄位:

頭欄位 描述
Accept 列出客戶支援的內容型別 (application/sdp is the only supported type).

DESCRIBE 命令的應答訊息包含如下附加的頭欄位:

頭欄位 描述
Content-Type 內容型別 (application/sdp).
Content-Length SDP 描述串的長度.
Content-Base 如果 SDP 描述串中使用了相對 URL, 這裡是相關的基本 URL.

例如:

請求

DESCRIBE rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 0
User-Agent: Vision MC
Accept: application/sdp
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 0
Content-Type: application/sdp
Content-Base: rtsp://myserver/live.mp4
Date: Wed, 16 Jul 2008 12:48:47 GMT
Content-Length: 847
v=0
o=- 1216212527554872 1216212527554872 IN IP4 myserver
s=Media Presentation
e=NONE
c=IN IP4 0.0.0.0
b=AS:50064
t=0 0
a=control:rtsp://myserver/live.mp4
&resolution=640x480
a=range:npt=0.000000-
m=video 0 RTP/AVP 96
b=AS:50000
a=framerate:30.0
a=control:rtsp://myserver/live.mp4?trackID=1
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; profile-level-id=420029; sprop-parameter-sets=Z0IAKeKQFAe2AtwEBAaQeJEV,aM48gA==
m=audio 0 RTP/AVP 97
b=AS:64
a=control:rtsp://myserver/live.mp4?trackID=2
a=rtpmap:97 mpeg4-generic/16000/1
a=fmtp:97 profile-level-id=15; mode=AAC-hbr;config=1408; SizeLength=13; IndexLength=3;IndexDeltaLength=3; Profile=1; bitrate=64000;

3.4 RTSP OPTIONS

OPTIONS 請求用於返回服務端支援的 RTSP 命令列表 。也可以定時傳送這個請求來保活相關的 RTSP 會話。

OPTIONS 命令的應答訊息包含如下附加的頭欄位:

頭欄位 描述
Public 指出支援的 RTSP 命令.

例如:列出支援的 RTSP 命令.

請求

OPTIONS * RTSP/1.0
CSeq: 1
User-Agent: Vision MC
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 1
Session: 12345678
Public: DESCRIBE, GET_PARAMETER, PAUSE, PLAY, SETUP, SET_PARAMETER, TEARDOWN
Date: Wed, 16 Jul 2008 12:48:48 GMT

3.5 RTSP SETUP

SETUP 命令用於配置資料交付的方法。

SETUP 請求和應答需要一個同樣的附加的頭欄位:

頭欄位 描述
Transport 指出如何傳輸資料流。分別支援 RTP/AVP;unicast;client_port=port1-port2 RTP/AVP;multicast;client_port=port1-port2 RTP/AVP/TCP;unicast 等不同的傳輸方式

這個請求的應答返回一個必須在流控制命令 (如 PLAY,PAUSE,TEARMDOWN) 中使用的會話 ID。 如果這個 Session 頭欄位包含了 timemout 引數, 除非有保活,否則會話會在超時時間後被關閉。會話可以通過傳送包含 Session ID 的 RTSP 請求 (如 OPTIONS,GET_PARAMETER) 給服務端來保活。 或者使用 RTCP 訊息。不支援中間重新更改傳輸引數。

例如: 在第一個 SETUP 請求的應答中返回會話的 ID。並且後續的請求中都包含這個會話 ID。

請求

SETUP rtsp://myserver/live.mp4?trackID=1 RTSP/1.0
CSeq: 2
User-Agent: Vision MC
Transport: RTP/AVP;unicast;client_port=20000-20001
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 2
Session: 12345678; timeout=60
Transport: RTP/AVP;unicast;client_port=20000-20001;server_port=50000-50001;ssrc=B0BA7855;mode="PLAY"
Date: Wed, 16 Jul 2008 12:48:47 GMT

例如:

請求

SETUP rtsp://myserver/live.mp4
trackID=2 RTSP/1.0
CSeq: 3
User-Agent: Vision MC
Transport: RTP/AVP;unicast;client_port=20002-20003
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 3
Session: 12345678; timeout=60
Transport: RTP/AVP;unicast;client_port=20002-20003;server_port=50002-50003;ssrc=D7EB59C0;mode="PLAY"
Date: Wed, 16 Jul 2008 12:48:48 GMT

Transport 頭欄位定義:

	Transport           =    "Transport" ":"
                          1\#transport-spec
	transport-spec      =    transport-protocol/profile[/lower-transport]
                          parameter
	transport-protocol  =    "RTP"
	profile             =    "AVP"
	lower-transport     =    "TCP" | "UDP"
	parameter           =    ( "unicast" | "multicast" )
                      |    ";" "destination" [ "=" address ]
                      |    ";" "interleaved" "=" channel [ "-" channel ]
                      |    ";" "append"
                      |    ";" "ttl" "=" ttl
                      |    ";" "layers" "=" 1*DIGIT
                      |    ";" "port" "=" port [ "-" port ]
                      |    ";" "client_port" "=" port [ "-" port ]
                      |    ";" "server_port" "=" port [ "-" port ]
                      |    ";" "ssrc" "=" ssrc
                      |    ";" "mode" = <"> 1\#mode <">
	ttl                 =    1*3(DIGIT)
	port                =    1*5(DIGIT)
	ssrc                =    8*8(HEX)
	channel             =    1*3(DIGIT)
	address             =    host
	mode                =    <">Method <"> | Method
	Example:
	Transport: RTP/AVP;multicast;ttl=127;mode="PLAY",
            RTP/AVP;unicast;client_port=3456-3457;mode="PLAY"

3.6 RTSP PLAY

這個 PLAY 用於啟動 (當暫停時重啟) 交付資料給客戶端. PLAY 命令的應答訊息包含如下附加的頭欄位:

頭欄位 描述
Range 播放時間段.
RTP-Info 關於 RTP 流的資訊。包含相關的流的第一個包的序列號。

例如:

請求

PLAY rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 4
User-Agent: Vision MC
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 4
Session: 12345678
Range: npt=0.645272-
RTP-Info: url=rtsp://myserver/live.mp4?trackID=1;seq=46932;rtptime=1027887748, url=rtsp://myserver/live.mp4?trackID=2;seq=3322;rtptime=611053482
Date: Wed, 16 Jul 2008 12:48:48 GMT

例如: Play back the recording “myrecording”.

請求

PLAY rtsp://myserver/live.mp4?recordingid=”myrecording” RTSP/1.0
CSeq: 4
User-Agent: Vision MC
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

3.7 RTSP PAUSE

PAUSE 請求用於臨時停止服務端的資料的交付。使用 PLAY 來重新啟動資料交付。

例如:

請求

PAUSE rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 5
User-Agent: Vision MC
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 5
Session: 12345678
Date: Wed, 16 Jul 2008 12:48:49 GMT

3.8 RTSP TEARDOWN

TEARDOWN 請求用於終止來自服務端的資料的傳輸。

例如:

請求

TEARDOWN rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 6
User-Agent: Vision MC
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 6
Session: 12345678
Date: Wed, 16 Jul 2008 12:49:01 GMT

3.9 RTSP SET_PARAMETER

SET_PARAMETER 命令用於請求儘快生成一個 I 幀。例如當開始錄影的時候。

必須包含 X-Request-Key-Frame: 1 的頭欄位。

請求

SET_PARAMETER rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 7
Session: 12345678
Authorization: Basic cm9vdDpwYXNz
X-Request-Key-Frame: 1
Content-Type: text/parameters
Content-Length: 19

Renew-Stream: yes

應答

RTSP/1.0 200 OK
CSeq: 8
Session: 12345678
Date: Wed, 16 Jul 2008 13:01:25 GMT

3.10 RTSP GET_PARAMETER

標準協議中 GET_PARAMETER 可以用於查詢引數狀態, 目前裝置主要通過 GET 命令來查詢裝置引數, 所以 GET_PARAMETER 用處不大, 目前主要用來用做會話保活請求.

請求

GET_PARAMETER rtsp://myserver/live.mp4 RTSP/1.0
CSeq: 7
Session: 12345678
Authorization: Basic cm9vdDpwYXNz

應答

RTSP/1.0 200 OK
CSeq: 8
Session: 12345678
Date: Wed, 16 Jul 2008 13:01:25 GMT

3.11 RTSP 代理伺服器擴充套件協議

3.11.1 設備註冊

前端裝置通過向 RTSP 代理伺服器傳送 OPTIONS 命令進行註冊

註冊的時候, 必須包含如下的頭欄位:

  • X-Proxy-ID: 前端裝置的序列號.
  • X-LocalAddress: 前端裝置的本地 IP 地址.

3.11.2 連線請求

服務端通過向前端裝置傳送 OPTIONS 命令請求新的 RTSP 連線

這個方法主要用於多通道的前端裝置.

請求的時候, 必須包含如下的頭欄位:

  • X-Invite: 要請求的通道的 URL.

3.11.2 註冊通道連線

前端裝置收到服務端的連線請求時, 將向服務端建立一個新的 TCP 連線, 並通過傳送 OPTIONS 命令進行註冊新的通道.

註冊的時候, 必須包含如下的頭欄位:

  • X-Proxy-ID: 前端裝置的序列號.
  • X-LocalAddress: 前端裝置的本地 IP 地址.

例如:

註冊: 前端裝置 => 轉發伺服器

OPTIONS * RTSP/1.0
X-Proxy-ID: 0006F609CA03
X-LocalAddress: 192.168.1.192:2100
CSeq: 13
User-Agent: Linux/2.6.14,M898v2/3.10.218,(MAC:0006F609CA03)

請求建立通道連線, 一般一個通道建立一個連線.

OPTIONS /live/0006F609CA03 RTSP/1.0
X-Invite: /live/0006F609CA03/live2.mp4
CSeq: 0

前端裝置收到上面的請求後, 向轉發伺服器建立一個新的連線, 併發送如下的 OPTIONS 命令

OPTIONS * RTSP/1.0
X-Proxy-Channel: /live/0006F609CA03/live2.mp4
X-LocalAddress: 192.168.1.192:2757
CSeq: 1
User-Agent: Linux/2.6.14,M898v2/3.10.218,(MAC:0006F609CA03)

X-Proxy-Channel: 用於指示當前連線繫結的通道, 和 上面的 X-Invite 頭欄位的值必須完全相同.

3.12 RTSP/RTP 交錯傳輸方式.

實現 RTSP 的系統必須支援通過 TCP 傳輸 RTSP 資料包,並支援 UDP。對 UDP 和 TCP,RTSP 伺服器的預設埠都是 554。許多目的一致的 RTSP 包被打包成單個低層 UDP 或 TCP 流。RTSP 資料可與 RTP 和 RTCP 包交錯傳輸, 即可以通過 TCP 傳輸 RTP 包。不像 HTTP,RTSP 訊息必須總是包含一個內容長度頭 (Content-Length),無論訊息是否包含訊息內容。如果沒有指定訊息內容的長度則預設訊息的內容的長度為 0。

當 RTP 通過 TCP 和 RTSP 訊息交錯傳輸時, 必須在 RTP 包前加 4 個位元組長度的頭, 它的結構如下:

BYTE  必須是 “$” or 0x24
BYTE  Channel id ,在 SETUP 訊息中 Transport 頭欄位中 interleaved 引數指定.
WORD  資料包的長度(從接下來的資料開始算起, 不包括這 4 個位元組的頭的長度)

例如:

 C->S: SETUP rtsp://foo.com/bar.file RTSP/1.0
           CSeq: 2
           Transport: RTP/AVP/TCP;interleaved=0-1

     S->C: RTSP/1.0 200 OK
           CSeq: 2
           Date: 05 Jun 1997 18:57:18 GMT
           Transport: RTP/AVP/TCP;interleaved=0-1
           Session: 12345678

     C->S: PLAY rtsp://foo.com/bar.file RTSP/1.0
           CSeq: 3
           Session: 12345678

     S->C: RTSP/1.0 200 OK
           CSeq: 3
           Session: 12345678
           Date: 05 Jun 1997 18:59:15 GMT
           RTP-Info: url=rtsp://foo.com/bar.file;
             seq=232433;rtptime=972948234

     S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
     S->C: $\000{2 byte length}{"length" bytes data, w/RTP header}
     S->C: $\001{2 byte length}{"length" bytes  RTCP packet}

4 SDP 協議

4.1 SDP 協議簡介

會話描述協議(SDP)為會話通知、會話邀請和其它形式的多媒體會話初始化等目的提供了多媒體會話描述。

會話目錄用於協助多媒體會議的通告,併為會話參與者傳送相關設定資訊。SDP 即用於將這種資訊傳輸到接收端。SDP 完全是一種會話描述格式 ― 它不屬於傳輸協議 ― 它只使用不同的適當的傳輸協議,包括會話通知協議(SAP)、會話初始協議(SIP)、實時流協議(RTSP)、MIME 擴充套件協議的電子郵件以及超文字傳輸協議(HTTP)。

SDP 的設計宗旨是通用性,它可以應用於大範圍的網路環境和應用程式,而不僅僅侷限於組播會話目錄,但 SDP 不支援會話內容或媒體編碼的協商。

SDP 文字資訊包括:

  • 會話名稱和意圖;
  • 會話持續時間;
  • 構成會話的媒體;
  • 有關接收媒體的資訊(地址等)。

Session description

v=  (protocol version)
o=  (owner/creator and session identifier).
s=  (session name)
i=* (session information)
u=* (URI of description)
e=* (email address)
p=* (phone number)
c=* (connection information - not required if included in all media)
b=* (bandwidth information)

One or more time descriptions (see below)

z=* (time zone adjustments)
k=* (encryption key)
a=* (zero or more session attribute lines)

Zero or more media descriptions (see below)

Time description

t=  (time the session is active)
r=* (zero or more repeat times)

Media description

m=  (media name and transport address)
i=* (media title)
c=* (connection information - optional if included at session-level)
b=* (bandwidth information)
k=* (encryption key)
a=* (zero or more media attribute lines)

4.2 協議結構

SDP 資訊是文字資訊,採用 UTF-8 編 碼中的 ISO 10646 字符集。SDP 會話描述如下:(標註 * 符號的表示可選欄位):

* v = (協議版本)
* o = (所有者/建立者和會話識別符號)
* s = (會話名稱)
* i = * (會話資訊)
* u = * (URI 描述)
* e = * (Email 地址)
* p = * (電話號碼)
* c = * (連線資訊 ― 如果包含在所有媒體中,則不需要該欄位)
* b = * (頻寬資訊)

一個或更多時間描述(如下所示):

* z = * (時間區域調整)
* k = * (加密金鑰)
* a = * (0 個或多個會話屬性行)
* 0個或多個媒體描述(如下所示)

時間描述

* t = (會話活動時間)
* r = * (0或多次重複次數)

媒體描述

* m = (媒體名稱和傳輸地址)
* i = * (媒體標題)
* c = * (連線資訊 — 如果包含在會話層則該欄位可選)
* b = * (頻寬資訊)
* k = * (加密金鑰)
* a = * (0 個或多個會話屬性行

5 H.264 視訊 RTP 負載格式

5.1. 網路抽象層單元型別 (NALU)

NALU 頭由一個位元組組成, 它的語法如下:

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+
F: 1 個位元.
forbidden_zero_bit. 在 H.264 規範中規定了這一位必須為 0.
NRI: 2 個位元.
nal_ref_idc. 取 00 ~ 11, 似乎指示這個 NALU 的重要性, 如 00 的 NALU 解碼器可以丟棄它而不影響影象的回放. 不過一般情況下不太關心這個屬性.
Type: 5 個位元.
nal_unit_type. 這個 NALU 單元的型別. 簡述如下:
  0     沒有定義
  1-23  NAL單元  單個 NAL 單元包.
  24    STAP-A   單一時間的組合包
  25    STAP-B   單一時間的組合包
  26    MTAP16   多個時間的組合包
  27    MTAP24   多個時間的組合包
  28    FU-A     分片的單元
  29    FU-B     分片的單元
  30-31 沒有定義

5.2. 打包模式

下面是 RFC 3550 中規定的 RTP 頭的結構.

       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |V=2|P|X|  CC   |M|     PT      |       sequence number         |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                           timestamp                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |           synchronization source (SSRC) identifier            |
      +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
      |            contributing source (CSRC) identifiers             |
      |                             ....                              |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

負載型別 Payload type (PT): 7 bits

序列號 Sequence number (SN): 16 bits

時間戳 Timestamp: 32 bits

H.264 Payload 格式定義了三種不同的基本的負載(Payload)結構. 接收端可能通過 RTP Payload 的第一個位元組來識別它們. 這一個位元組類似 NALU 頭的格式, 而這個頭結構的 NAL 單元型別欄位 則指出了代表的是哪一種結構,

這個位元組的結構如下, 可以看出它和 H.264 的 NALU 頭結構是一樣的.

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+

欄位 Type: 這個 RTP payload 中 NAL 單元的型別. 這個欄位和 H.264 中型別欄位的區別是, 當 type 的值為 24 ~ 31 表示這是一個特別格式的 NAL 單元, 而 H.264 中, 只取 1~23 是有效的值.

  24    STAP-A   單一時間的組合包
  25    STAP-B   單一時間的組合包
  26    MTAP16   多個時間的組合包
  27    MTAP24   多個時間的組合包
  28    FU-A     分片的單元
  29    FU-B     分片的單元
  30-31 沒有定義

可能的結構型別分別有:

1. 單一 NAL 單元模式
即一個 RTP 包僅由一個完整的 NALU 組成. 這種情況下 RTP NAL 頭型別欄位和原始的 H.264的 NALU 頭型別欄位是一樣的.
2. 組合封包模式
即可能是由多個 NAL 單元組成一個 RTP 包. 分別有4種組合方式: STAP-A, STAP-B, MTAP16, MTAP24. 那麼這裡的型別值分別是 24, 25, 26 以及 27.
3. 分片封包模式
用於把一個 NALU 單元封裝成多個 RTP 包. 存在兩種型別 FU-A 和 FU-B. 型別值分別是 28 和 29.

2.1 單一 NAL 單元模式

對於 NALU 的長度小於 MTU 大小的包, 一般採用單一 NAL 單元模式. 對於一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用於標示這是一個

NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個位元組, 其後都是 NALU 單元內容. 打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他資料封包的 RTP 包即可.

       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |F|NRI|  type   |                                               |
      +-+-+-+-+-+-+-+-+                                               |
      |                                                               |
      |               Bytes 2..n of a Single NAL unit                 |
      |                                                               |
      |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                               :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

如有一個 H.264 的 NALU 是這樣的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]

這是一個序列引數集 NAL 單元. [00 00 00 01] 是四個位元組的開始碼, 67 是 NALU 頭, 42 開始的資料是 NALU 內容. 封裝成 RTP 包將如下:

[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]

即只要去掉 4 個位元組的開始碼就可以了.

2.2 組合封包模式

其次, 當 NALU 的長度特別小時, 可以把幾個 NALU 單元封在一個 RTP 包中.

  
       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                          RTP Header                           |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         NALU 1 Data                           |
      :                                                               :
      +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |               | NALU 2 Size                   | NALU 2 HDR    |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                         NALU 2 Data                           |
      :                                                               :
      |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                               :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

2.3 Fragmentation Units (FUs).

而當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包. 也稱為 Fragmentation Units (FUs).

       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
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      | FU indicator  |   FU header   |                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+                               |
      |                                                               |
      |                         FU payload                            |
      |                                                               |
      |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                               :...OPTIONAL RTP padding        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

      Figure 14.  RTP payload format for FU-A

The FU indicator octet has the following format:

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+

The FU header has the following format:

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |S|E|R|  Type   |
      +---------------+

如有一個 H.264 的 NALU 是這樣的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ] 
[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ] 

這是一個序列引數集 NAL 單元. [00 00 00 01] 是四個位元組的開始碼, 67 是 NALU 頭, 42 開始的資料是 NALU 內容. 封裝成 RTP 包可能如下:

[ RTP Header ] [78, STAP-A NAL HDR, 一個位元組 ] [長度, 兩個位元組] [ 67 42 A0 1E 23 56 0E 2F ...] [長度, 兩個位元組] [ 67 42 A0 1E 23 56 0E 2F... ] 

5.3. SDP 引數

下面描述瞭如何在 SDP 中表示一個 H.264 流:

  • . "m=" 行中的媒體名必須是 "video"
  • . "a=rtpmap" 行中的編碼名稱必須是 "H264".
  • . "a=rtpmap" 行中的時鐘頻率必須是 90000.
  • . 其他引數都包括在 "a=fmtp" 行中.

如:

  m=video 49170 RTP/AVP 98
  a=rtpmap:98 H264/90000
  a=fmtp:98 profile-level-id=42A01E; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==

下面介紹一些常用的引數.

3.1 packetization-mode:

表示支援的封包模式.

  • 當 packetization-mode 的值為 0 時或不存在時, 必須使用單一 NALU 單元模式.
  • 當 packetization-mode 的值為 1 時必須使用非交錯(non-interleaved)封包模式.
  • 當 packetization-mode 的值為 2 時必須使用交錯(interleaved)封包模式.

這個引數不可以取其他的值.

3.2 sprop-parameter-sets:

這個引數可以用於傳輸 H.264 的序列引數集和影象引數 NAL 單元. 這個引數的值採用 Base64 進行編碼. 不同的引數集間用","號隔開.

3.3 profile-level-id:

這個引數用於指示 H.264 流的 profile 型別和級別. 由 Base16(十六進位制) 表示的 3 個位元組. 第一個位元組表示 H.264 的 Profile 型別, 第 三個位元組表示 H.264 的 Profile 級別.

3.4 max-mbps:

這個引數的值是一個整型, 指出了每一秒最大的巨集塊處理速度.

6 示例

設備註冊:

WARN  [9516] 16:36:29 OPTIONS * RTSP/1.0
X-Proxy-ID: 0006F609CA03
X-LocalAddress: 192.168.1.192:4314
CSeq: 14
User-Agent: Linux/2.6.14,M898v2/3.10.218,(MAC:0006F609CA03)

客戶端請求第二個通道

INFO  [9516] 16:36:37 New Connection: 192.168.1.21 ...
WARN  [9516] 16:36:37 DESCRIBE /live/0006F609CA03/live2.mp4 RTSP/1.0
Accept: application/sdp
CSeq: 1
User-Agent: NewStream Vision Player 3.3

轉發伺服器還沒有建立這個通道, 請求前端裝置建立這個通道的連線.

DEBUG [9516] 16:36:37 Invite: /live/0006F609CA03/live2.mp4
DEBUG [9516] 16:36:37 OPTIONS /live/0006F609CA03 RTSP/1.0
X-Invite: /live/0006F609CA03/live2.mp4
CSeq: 0

WARN  [9516] 16:36:37 RTSP/1.0 200 OK
CSeq: 0
Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SET_PARAMETER, GET_PARAMETER
Server: IPCAM Embed Stream Server
Date: Tue, 13 Jul 2010 16:36:40 +0800

前端裝置發起一個新的連線

INFO  [9516] 16:36:37 New Connection: 192.168.1.192 ...
DEBUG [9516] 16:36:37 /live/0006F609CA03/live2.mp4: /live2.mp4
DEBUG [9516] 16:36:37 Add Source (/live/0006F609CA03/live2.mp4)
WARN  [9516] 16:36:37 AsyncSend: WSASend() failed with error 10057
INFO  [9516] 16:36:37 AttachMediaChannel: Bind to /live/0006F609CA03/live2.mp4

DEBUG [9516] 16:36:37 /live/0006F609CA03/live2.mp4: /live2.mp4
DEBUG [9516] 16:36:37 OnStateChanged: 1
DEBUG [9516] 16:36:37 OnStateChanged: 2
WARN  [9516] 16:36:37 OPTIONS * RTSP/1.0
X-Proxy-Channel: /live/0006F609CA03/live2.mp4
X-LocalAddress: 192.168.1.192:4315
CSeq: 1
User-Agent: Linux/2.6.14,M898v2/3.10.218,(MAC:0006F609CA03)


INFO  [9668] 19:35:20 New Connection:  ...

7 參考程式碼

/** 傳送指定的 NALU 單元. */ 
int GEPlayback::SendNaluPacket( BYTE* sliceData, int sliceSize, BOOL isEnd, 
BOOL isVideo, int type, time_t pts, INT64 timestamp ) 
{ 
	// NALU 小於最大 RTP 包大小的情況 
	if (sliceSize < 1350) { 
		return SendPacket(sliceData, sliceSize, isEnd, TRUE, type, pts, timestamp); 
	} 

	// 如果一個 NALU 大於最大的 RTP 包的大小, 則需要把它進行分片後打包傳送 
	BYTE buffer[1500]; 

	BYTE nalHeader = sliceData[0]; // NALU 頭 
	BYTE* data = sliceData + 1; 
	int leftover = sliceSize - 1; 
	BOOL isStart = TRUE; 

	while (leftover > 0) { 
		int size = MIN(1350, leftover); 
		isEnd = (size == leftover); 

		// 構建 FU 頭 
		buffer[0] = (nalHeader & 0x60) | 28; // FU indicator 
		buffer[1] = (nalHeader & 0x1f); // FU header 
		if (isStart) { 
			buffer[1] |= 0x80; 
		} 

		if (isEnd) { 
			buffer[1] |= 0x40; 
		} 

		memcpy(buffer + 2, data, size); 
		SendPacket(buffer, size + 2, isEnd, TRUE, type, pts, timestamp); 

		leftover -= size; 
		data += size; 
		isStart = FALSE; 
	} 

	return sliceSize; 
}