1. 程式人生 > >rfc 5109 前向糾錯碼(FEC)的RTP荷載格式

rfc 5109 前向糾錯碼(FEC)的RTP荷載格式

TAG:
 

本備忘錄狀態
    本文件講述了一種Internet通訊的標準Internet跟蹤協議,並對其改進提出了討論和建議。請參考最新版本的"Internet Official Protocol Standards"(STD1)來獲得本協議的標準化程序和狀態,此備忘錄的釋出不受任何限制。

版權注意
    版權歸因特網協會(1999)所有,保留一切權利。

摘要
    本文件規定了一般性的前向糾錯的媒體資料流的RTP打包格式。這種格式針對基於異或操作的FEC演算法進行了特殊設計,它允許終端系統使用任意長度的糾錯碼,並且可以同時恢復出荷載資料和RTP頭中的關鍵資料。由於FEC作為一個分離的資料流進行傳送,這種方案可以向後相容那些沒有實現FEC解碼器的接收 終端。對於那樣的終端來說,可以簡單地將FEC資料丟掉。

目錄
1    簡介                        2
2    術語                        2
3    基本操作                    3
4    監督碼                      3
5    RTP媒體資料包結構           5
6    FEC包結構                   5
6.1 FEC包的RTP包頭              5
6.2 FEC頭                       5
7    保護操作                    6
8    恢復過程                    7
8.1 重建                        7
8.2 何時進行恢復                8
9    例子                        11
10   冗餘編碼中使用FEC的用法     13
11   在SDP中表示FEC              14
11.1 FEC作為獨立的流傳輸         14
11.2 在冗餘編碼中使用FEC         15
11.3 在RTSP中的用法              16
12   安全性問題                  16
13   致謝                        17
14   作者地址                    17
15   參考書目                    17
16   版權宣告                    18
     致謝                        18

1    簡介
    在Internet上用分組傳送話音的質量不夠好的一個重要原因是比較高的丟包率。尤其在廣域網中,這個問題相當突出。不幸的是,實時多媒體業務對於延時 的要求相當嚴格,因此不大可能通過重傳來解決丟包的問題。正是出於這個原因,大家提出用前向糾錯(FEC)來解決Internet上的丟包問題[1] [2]。尤其是對於傳統糾錯碼如校驗碼、RS碼、漢明碼等的使用引起了很多人的注意。為了能夠更好地應用這些糾錯碼,必須有相關的協議來支援。

    本文件定義了一種RTP的荷載格式,允許對於實時媒體流進行一般性的前向糾錯。在這裡“一般性”指的是
(1)與被保護的媒體型別無關,即音訊、視訊或其它;
(2)足夠靈活,能夠支援多種FEC機制;
(3)自適應性,可以方便的修改FEC方案而不需要帶外的信令支援;
(4)支援若干種不同的FEC包的傳輸機制。

2    術語
    本文件中使用了下面這些術語:
媒體荷載:一段待傳輸的未加保護的使用者資料。媒體荷載放在一個RTP包的內部。
媒體頭:包含媒體荷載的包的RTP頭
媒體包:媒體荷載與媒體頭合起來稱作媒體包
FEC包:傳送端將媒體包作為前向糾錯演算法的輸入,輸出除了這些媒體包之外,還有一些新的資料包稱作FEC包。FEC包的格式在本文件中進行說明。
FEC頭:FEC包的頭資訊稱作FEC頭。
FEC荷載:FEC荷載是FEC包中的荷載。
關聯的:一個FEC包稱作與一個或幾個媒體包是關聯的,如果在這個FEC包的產生過程中這幾個媒體包用作EC演算法的輸入關鍵詞“必須”,“必須不”,“要求的”,“會“,”不會“,“應該”,“不應該”,“建議的”,“或許”,“可選的”在RFC2119[4]中解釋。

3    基本操作
    這裡描述的荷載格式用於一個RTP會話中的某一端想要用FEC來保護它所傳送的媒體資料流的情況。這種格式所支援的FEC是基於簡單異或校驗的糾錯演算法。 傳送端從媒體資料流中取出若干個包,並對它們整個施以異或操作,包括RTP頭。基於這樣一個過程,可以得到一個包含FEC資訊的RTP包。這個包可以被接 收端用來恢復任何一個用來產生它的包。本文件中並未規定多少個媒體包合起來產生一個FEC包。不同引數的選取會導致在overhead,延時和恢復能力之 間的一個不同的折中方案。第4節給出了一些可能的組合。
    傳送端需要告訴接收端哪些媒體包被用來產生了一個FEC包,這些資訊都包含在荷載資訊中。每個FEC包中包含一個24位元的mask,如果mask的第i 個位元為1,序號為N+i的媒體包就參與了這個FEC包的生成。N稱作基序號,也在FEC包中傳送。通過這樣一種方案就可以以相當小的overhead來 用任意的FEC糾錯方案恢復丟失的資料包。
    本文件也描述瞭如何使接收端在不瞭解具體糾錯碼細節的情況下利用FEC的方法。這就給了傳送端更大的靈活性,它可以根據網路狀態而自適應選擇糾錯碼,而接收端仍能夠正確解碼並用於恢復丟失的包。
    傳送端生成FEC包之後,就把它們發給接收端,同時,傳送端也照常傳送原來的媒體資料包,就好像沒有FEC一樣。這樣對於沒有FEC解碼能力的接收端,媒 體流也照常可以接收並解碼。然而,對於某些糾錯碼來說,原始的媒體資料包是不需要傳輸的,僅靠FEC包就足以恢復丟失的包了。這類碼就具有一個很大的缺 點,就是要求所有的接收者都具有FEC解碼能力。這類碼在本文件中也是支援的。
    FEC包並不與媒體包在同一個RTP流中傳輸,而是在一個獨立的流中傳輸,或者作為冗餘編碼(redundantencoding)中的次編碼 (secondaryencoding)來傳輸[5]。當在另一個流中傳輸時,FEC包有它們自己的序號空間。FEC包的時間戳是從對應的媒體包中得來 的,同樣是單調遞增。因此,這樣的FEC包可以很好地應用於任何具有固定差值的包頭壓縮方案。本文並沒有規定何為“一個獨立的流”,而把它留給上層協議和 具體應用去定義。對於多播的情況,“一個獨立的流”可以通過不同的多播組來實現,或者同一個組的不同埠,或者同樣的組和埠中不同的SSRC。對於單播 的情況,可以使用不同的埠或者不同的SSRC。
    這些方法都各有其優缺點,選用哪一種取決於具體的應用。接收端收到FEC包和媒體包之後,先判斷是否有媒體包丟失。如果沒有,FEC包就直接被丟棄。如果 有丟包,就使用接收到的FEC包和媒體包來進行丟包的重建。這樣一個重建過程是很精確的,荷載以及包頭的大部分資料都可以完全恢復出來。
    按照本協議來進行打包的RTP包可以使用一個動態RTP荷載型別號來通知接收端。

4    監督碼
    我們定義f(x,y,..)為資料包x,y,…等的異或,這個函式的輸出也是一個數據包,稱作監督包。為簡單起見,我們假定監督包就是輸入的各個包的對應位元異或得到。詳細的過程描述在第6節中給出。
用監督碼來恢復資料包是通過對一組資料包生成一個或多個監督包來完成的。為了提高編碼的效率,這些監督包必須是資料包的線性無關的組合生成的。某一個特定 的組合就稱為一個監督碼。對於k個一組的資料包,生成n-k個監督包,這樣的監督碼認為是同一類監督碼。對於給定的n,k,可能的監督碼有很多。荷載格式 並未要求使用某個特定的監督碼。

舉個例子,考慮這樣一種監督碼,輸入為兩個資料包,輸出為1一個監督包。如果原始媒體資料包是a,b,c,d,傳送端送出的包如下所示:

abcd<--媒體流
f(a,b)f(c,d)<--FEC流
    時間從左向右遞增。在這個例子裡,糾錯碼帶來了50%的overhead。但是如果b丟失了,用a和f(a,b)就可以恢復出b。
下面還給出了一些其它的監督碼。其中每一個的原始媒體資料流都包含資料包a,b,c,d等等。

方案1
--------
    這個方案與上面的例子很類似。區別在於,並不是傳送b之後再發送f(a,b)。f(a,b)在b之前就傳送出去了。顯然這樣做會給傳送端帶來額外的延時,但是用這種方案能夠恢復出突發的連續兩個丟包。傳送端送出的包如下所示:
abcde<--媒體流
f(a,b)f(b,c)f(c,d)f(d,e)<--FEC流

方案2
--------
    事實上,並沒有嚴格規定一定要傳送原始媒體資料流。在這個方案中,只傳送FEC資料包。這種方案能夠恢復出所有單個的丟包和某些連續的丟包,而且overhead比方案1略小一些。傳送端送出的資料包如下所示:
f(a,b)f(a,c)f(a,b,c)f(c,d)f(c,e)f(c,d,e)<--FEC流

方案3
--------
    這種方案要求接收端在恢復原始媒體資料包時等待4個數據包間隔的時間,也就是在接收端引入了4個數據包的延時。它的優越性在於它能夠恢復出單個丟包,連續兩個丟包乃至連續三個丟包。傳送端送出的資料包如下所示:
abcd<--媒體流
f(a,b,c)f(a,c,d)f(a,b,d)<--FEC流

5    RTP媒體資料包結構
    媒體資料包的結構並不受FEC的影響。如果FEC包作為一個獨立的流進行傳輸,媒體資料包的傳輸就與不使用FEC時完全沒有區別。如果FEC作為一個冗餘 編碼(redundantcodec)來進行傳輸,媒體資料包就作為RFC2198[5]中定義的主編碼(primarycodec)。
這樣一種編碼方式是非常高效的。如果只使用了極少量的FEC,大部分資料包都是媒體資料包,這意味著overhead代表著FEC的冗餘資料量。

6    FEC包結構
    一個FEC包就是把一個FEC包頭和FEC包的荷載放進RTP包的荷載中組成的,如圖1所示。

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|RTP頭|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|FEC頭|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|FEC荷載|
||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
圖1:FEC包結構

6.1    FEC包的RTP包頭
    在FEC包的RTP包頭中,版本域設定為2,填充位通過保護操作計算得到,具體方法在後面給出。擴充套件位也是通過保護操作計算得到的。一般情況下,SSRC 的值應當與它所保護的媒體資料包的SSRC值一致。如果FEC流通過SSRC值來進行解複用的話,SSRC的值就有可能會不同。CC的值也是在保護操作中 計算出來。不管CC域為何值,CSRC列表永遠不存在。不管X位元為何值,頭擴充套件部分永遠不存在。標記位的值通過保護操作計算得出。
    對於次序號有一個標準的定義:當前包的次序號必須比前一個包的次序號大1。時間戳必須設定為當前這個FEC包傳送時對應的媒體流的RTP時鐘的值。不管使用何種FEC方案,FEC包頭中的TS值是單調遞增的。
    FEC包的荷載型別是動態確定的,即在帶外通過信令來協商確定的。按照RFC1889[3],RTP會話的某一方如果不能識別收到的RTP包的荷載型別的 話,就必須將其丟棄。這樣就很自然地提供了向後相容的能力。FEC機制可以用在一個多播的環境中,某些接收端具有FEC解碼能力,而某些不具有。

6.2    FEC頭
    FEC頭的長度為12個位元組,其格式如圖2所示。它包含一個SN基數域,長度恢復域,E域,PT恢復域,mask域以及TS恢復域。

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|SN基數|長度恢復|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|E|PT恢復|mask|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|TS恢復|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
圖2:FEC頭格式

    長度恢復域用來確定待恢復的資料包的長度。它的值是當前組中被保護的媒體資料包的長度(以位元組為單位)的二進位制和(逐位異或),用一個網路序的16位元無 符號整數表示。在這裡,媒體資料包的長度包括CSRC列表、擴充套件部分和填充的位元。這樣即使在媒體資料包長度不一致的情況下,也一樣可以使用FEC。舉個 例子,假定要用兩個媒體資料包的異或來產生一個FEC包,這兩個媒體資料包的長度分別為3(0b011)和5(0b101)個位元組,那麼長度恢復域的值就 是0b011xor0b101=0b110。
    位元E指示是否存在一個擴充套件部分。在當前版本中,這個位元必須設定為0。
    PT恢復域是通過對相關的媒體資料包的荷載型別域的值進行異或操作得到的,從而能夠用來恢復丟失包的荷載型別。
    Mask域長度為24個位元,如果其中的第i個位元設定為1,那麼序號為N+i的媒體資料包就與當前FEC包相關聯。其中N是SN基數域的值。最低位(LSB)對應於i=0,最高位(MSB)對應於i=23。
    SN基數域的值必須設定為與當前FEC包相關的媒體資料包中的最小的序號。這樣一個FEC包最多可以與連續24個媒體資料包相關聯。
    TS恢復域是通過計算相關聯的媒體資料包的時間戳的異或得到的。這樣就可以恢復出丟掉的資料包的時間戳。
    FEC包的荷載是對相關聯的媒體資料包的CSRC列表、RTP頭部擴充套件、媒體包荷載以及填充位元連在一起進行異或操作得到的。
    值得注意的是FEC包的長度有可能會比它保護的媒體資料包的長度大一點,因為多了一個FEC頭。如果FEC包的長度超出了下層協議允許的最大包長,這可能會給傳輸帶來很大的問題。

7    保護操作
    保護操作涉及到將RTP頭中的某些域與媒體包的荷載級聯起來,再加上填充位元,然後對這些序列計算它們的異或值。得到的位元序列就成為FEC包的某個組成 部分。對於每一個要保護的媒體包,按照下面的次序將各個資料域級聯起來生成一個位元序列,如果中間還插入了其它操作的話,最終結果必須與下面所描述的一 致:
o填充位(1位元)
o擴充套件位(1位元)
oCC(4位元)
o標記位(1位元)
o荷載型別(7位元)
o時間戳(32位元)
o長度恢復域的值(網路次序16位元無符號整數),也就是各個媒體資料包的荷載長度、CSRC列表長度以及填充位元長度的和異或的結果
o如果CC不為零,這裡是CSRC列表(變長)
o如果擴充套件位為1,這裡是頭部擴充套件(變長)
o荷載(變長)
o填充,如果存在的話(變長)
    需要注意的是最前面的填充位是整個位元序列的最重要位元(MSB)。
    如果各個媒體資料包的到的位元序列長度不相等,那麼每一個都必須填充到最長的序列那麼長。填充值可以是任意的,但必須填充在整個位元序列的最後。對所有這 些位元序列進行對位異或操作,就可以得到一個監督位元序列,這個監督位元序列就可以用來生成FEC包。稱這個位元序列為FEC位元序列。FEC位元序列中 的第一個位元填入FEC包的填充位,第二個位元填入FEC包的擴充套件位,接下來的四個位元填入FEC包的CC域,再下來的一個位元填入FEC包的標記位,然 後的七個位元寫入FEC包頭的PT恢復域,再後面的32個位元寫入FEC包頭的TS恢復域,再接下來的16個位元寫入FEC包頭中的長度恢復域。最後剩下 的位元就作為FEC包的荷載。

8    恢復過程
    FEC包能夠使終端系統有能力恢復出丟失的媒體資料包。丟失包的的包頭中的所有資料域,包括CSRC列表,擴充套件位,填充位,標記位以及荷載型別,都是可以恢復的。這一節描述進行恢復的過程。
    恢復過程中包含兩個不同的操作。第一個是確定需要用哪些包(包括媒體包和FEC包)來恢復一個丟失的包。這一步完成之後,第二步就是重建丟失的包。第二步 必須按照下面的規定來進行。第一步可以由實現者選擇任意的演算法來完成。不同的演算法會導致在複雜度和恢復丟包能力之間的一個不同的折中。

8.1    重建
    設T為可用來恢復媒體資料包xi的一組包(包括FEC包和媒體包),重建過程如下所述:
1. 對於T中的媒體資料包,按照上一節保護操作中所規定的那樣計算它們的位元序列。
2. 對於T中的FEC包,基本以同樣的方式來計算位元序列,不同點僅在於用PT恢復域的值取代荷載型別,用TS恢復域的值取代時間戳,並將CSRC列表、擴充套件位和填充位都設為null。
3. 如果某個媒體資料包生成的位元序列比FEC包生成的位元序列短,就把它填充到域FEC包生成的位元序列一樣長度。填充部分必須加在位元序列的最後,可以為任意值。
4. 對這些位元序列進行按位異或操作,得到一個恢復出的位元序列。
5. 建立一個新的資料包,12個位元組的標準RTP頭,沒有荷載。
6. 將這個新包的版本域設為2。
7. 將新包的填充位設為恢復出的位元序列的第一個位元。
8. 將新包的擴充套件位設為恢復出的位元序列的第二個位元。
9. 將新包的CC域設為恢復出的位元序列的接下來的4個位元。
10. 將新包的標記為設為恢復出的位元序列的接下來的一個位元。
11. 將新包的荷載型別設為恢復出的位元序列的接下來的7個位元。
12. 將新包的SN域設定為xi。
13. 將新包的TS域的值設定為恢復出的位元序列的接下來的32個位元。
14. 從恢復出的位元序列中取出接下來的16個位元,將其作為一個網路序的無符號整數,然後從恢復出的位元序列中取出這個整數那麼多的位元組,新增在新包之後,這代表新包的CSRC列表、擴充套件、荷載和填充。
15. 將新包的SSRC域設定為它所保護的媒體流的SSRC值。
    上面的這個過程能夠完全恢復出一個丟失的RTP包的包頭和荷載。

8.2    何時進行恢復
    前面一節討論了當要恢復一個序號為xi的包時,所有需要的包都可用時,如何來進行恢復。而並未涉及如何決定是否去試圖恢復某個包xi,以及如何確定是否有 足夠的資料來恢復這個包。這些問題將留給實現者去靈活設計,但我們將在本節給出一個可用於解決這些問題的簡單演算法。
    下面的這個演算法是用C語言寫的。程式碼中假定已經存在了幾個函式。recover_packet()的引數是一個包的序號和一個FEC包。用這個FEC包和 以前收到的資料包,這個函式能夠恢復出指定序號的資料包。add_fec_to_pending_list()將一個給定的FEC包加入到一個存放尚未用 於恢復操作的FEC包的連結串列中去。wait_for_packet()等待從網路上發來的一個包,

FEC包或者是資料包。remove_from_pending_list()將一個FEC包從連結串列中刪除。結構體packet包含一個布林變數 fec,當這個包為FEC包時fec為真,否則為假。當它是一個FEC包時,成員變數mask和snbase存放著FEC包頭中對應值;當它是一個媒體數 據包時,sn變數存放著包的序號。全域性陣列A用於指示出哪些媒體資料包已經收到了,而哪些還沒有。它是以包的序號為索引的。
    函式fec_recovery給出了這個演算法的實現。它等待網路上發來的資料包,當它收到一個FEC包時,就呼叫recover_with_fec(), 即嘗試用它來恢復。如果恢復操作不可能(資料不足),就把這個FEC包存起來備用。如果收到的包是一個媒體資料包,就記錄下它已經收到了,然後檢查以前的 FEC包是否現在可以進行恢復了。我們對待恢復出來的包就象從網路上收到這個包一樣,並會引發進一步的恢復嘗試。
    一個實際的實現需要用一個迴圈緩衝區來代替陣列A,以避免陣列緩衝區溢位。並且,下面的程式碼中並沒有釋放已經沒有任何用處的FEC包。一般來說,對FEC 包的釋放操作可以基於一個時間限制(playtime),這個時間限制取決於傳送端以多少個包為一組進行保護操作。當一個FEC包所保護的資料包的 playtime已經過去的時候,這個FEC包就不再有用了。

  1. typedefstruct packet_s{ 
  2. BOOLEAN fec;/*FECormedia*/
  3. int sn;/*SNofthepacket,formediaonly*/
  4. BOOLEAN mask[24];/*Mask,FEConly*/
  5. int snbase;/*SNBase,FEConly*/
  6. struct packet_s*next; 
  7. }packet; 
  8. BOOLEANA[65535]; 
  9. packet*pending_list; 
  10. packet*recover_with_fec(packet*fec_pkt){ 
  11. packet*data_pkt; 
  12. intpkts_present,/*numberofpacketsfromthemaskthatare 
  13. present*/
  14. pkts_needed,/*numberofpacketsneededisthenumberofones 
  15. inthemaskminus1*/
  16. pkt_to_recover,/*snofthepacketwearerecovering*/
  17. i; 
  18. pkts_present=0; 
  19. /*The number of packets needed is the number of ones in the mask 
  20.  minus1.The code below increments pkts_needed by the number 
  21.  of ones in the mask, so we initialize this to-1 so that the 
  22. final count is correct*/
  23. pkts_needed=-1; 
  24. /*Gothroughall24bitsinthemask,andcheckifwehave 
  25. allbutoneofthemediapackets*/
  26. for(i=0;i<24;i++){ 
  27. /*Ifthepacketishereandinthemask,incrementcounter*/
  28. if(A[i+fec_pkt->snbase]&&fec_pkt->mask[i])pkts_present++; 
  29. /*Countthenumberofpacketsneededaswell*/
  30. if(fec_pkt->mask[i])pkts_needed++; 
  31. /*Thepackettorecoveristheonewithabitinthe 
  32. maskthat'snothereyet*/
  33. if(!A[i+fec_pkt->snbase]&&fec_pkt->mask[i]) 
  34. pkt_to_recover=i+fec_pkt->snbase; 
  35. /*Ifwecanrecover,doso.Otherwise,returnNULL*/
  36. if(pkts_present==pkts_needed){ 
  37. data_pkt=recover_packet(pkt_to_recover,fec_pkt); 
  38. }else
  39. data_pkt=NULL; 
  40. return(data_pkt); 
  41. voidfec_recovery(){ 
  42. packet*p,/*packetreceivedorregenerated*/
  43. *fecp,/*fecpacketfrompendinglist*/
  44. *pnew;/*newpacketsrecovered*/
  45. while(1){ 
  46. p=wait_for_packet();/*getpacketfromnetwork*/
  47. while(p){ 
  48. /*ifit'sanFECpacket,trytorecoverwithit.Ifwecan't, 
  49. storeitforlaterpotentialuse.Ifwecanrecover,actas 
  50. iftherecoveredpacketisreceivedandtrytorecoversome 
  51. more.Otherwise,ifit'sadatapacket,markitasreceived, 
  52. andcheckifwecannowrecoveradatapacketwiththelist 
  53. ofpendingFECpackets*/
  54. if(p->fec==TRUE){ 
  55. pnew=recover_with_fec(p); 
  56. if(pnew) 
  57. A[pnew->sn]=TRUE; 
  58. else
  59. add_fec_to_pending_list(p); 
  60. /*Weassignpnewtopsincethewhileloopwillcontinue 
  61. torecoverbasedonpnotbeingNULL*/
  62. p=pnew; 
  63. }else
  64. /*Markthisdatapacketashere*/
  65. A[p->sn]=TRUE; 
  66. free(p); 
  67. p=NULL; 
  68. /*Gothroughpendinglist.Tryandrecoverapacketusing 
  69. eachFEC.Ifwearesuccessful,addthedatapacketto 
  70. thelistofreceivedpackets,removetheFECpacketfrom 
  71. thependinglist,sincewe'veusedit,andthentryto 
  72. recoversomemore*/
  73. for(fecp=pending_list;fecp!=NULL;fecp=fecp->next){ 
  74. pnew=recover_with_fec(fecp); 
  75. if(pnew){ 
  76. /*Thepacketisnowhere,aswe'verecoveredit*/
  77. A[pnew->sn]=TRUE; 
  78. /*OneFECpacketcanonlybeusedoncetorecover, 
  79. soremoveitfromthependinglist*/
  80. remove_fec_from_pending_list(fecp); 
  81. p=pnew; 
  82. break
  83. }/*for*/
  84. }/*p->fecwasfalse*/
  85. }/*whilep*/
  86. }/*while1*/

9    例子

    考慮這樣的情況,有兩個媒體資料包x和y要從SSRC2傳送出去。它們的序號分別為8和9,時間戳分別為3和5。x的荷載型別為11,y的荷載型別為18。x有十個位元組的荷載,y有11個位元組的荷載。y的標記位為1。x和y的RTP包頭分別如圖3和圖4所示。

媒體資料包x
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|10|0|0|0000|0|0001011|0000000000001000|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000011|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000010|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
版本:2
填充位:0
擴充套件位:0
標記位:0
PTI:11
SN:8
TS:3
SSRC:2
圖3:媒體包x的RTP頭

媒體包y
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|10|0|0|0000|1|0010010|0000000000001001|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000101|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000010|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

版本:2
填充位:0
擴充套件位:0
標記位:1
PTI:18
SN:9
TS:5
SSRC:2

圖4:媒體包y的RTP頭

    由這兩個包生成一個FEC包。我們假定用荷載型別值127來指示一個FEC包。得到的FEC包的RTP包頭如圖5所示。
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|10|0|0|0000|1|1111111|0000000000000001|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000101|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000010|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
版本:2
填充位:0
擴充套件位:0
標記位:1
PTI:127
SN:1
TS:5
SSRC:2
圖5:x,y的FEC包的RTP頭

FEC包的FEC頭如圖6所示。

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0000000000001000|0000000000000001|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|0011001|000000000000000000000011|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|00000000000000000000000000000110|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
SN基數:8[min(8,9)]
長度恢復域:1[8xor9]
E:0         
PTI恢復域:25[11xor18]
mask:3
TS恢復域:6[3xor5]
荷載長度為11個位元組
圖6:FEC包的FEC頭

10    冗餘編碼中使用FEC的用法
    我們可以把一個FEC包看成是對媒體的一個冗餘編碼(redundantencoding)。這樣一來,[5]中所描述的冗餘音訊資料的荷載格式就可以用 於FEC資料的打包。這個過程如下所述:上面的FEC操作作用於一個RTP媒體資料包組成的流上。這個流也就是RFC2198[5]中進行封裝之前的流。 換句話說,將待保護的媒體資料流封裝在標準的RTP媒體包中,然後進行前面定義過的FEC操作(有一點小的改動),生成一個FEC資料包的流。這裡與前面 不同的一點在於:在進行FEC操作之前,必須把待保護的RTP媒體資料包的RTP頭擴充套件、填充部分以及CSRC列表去掉,並且CC域、填充位、擴充套件位必須 設定為零,用這些修改之後的RTP媒體資料包去生成FEC包。需要注意的是傳送端要傳送出去的仍然是原來沒有修改的媒體資料包,只是在計算FEC包的時候 才去除掉這些域。
    一旦生成了FEC包,將媒體資料包中的荷載提取出來,作為RFC2198中定義的主編碼(primaryencoding),將FEC包中的FEC頭和荷 載提取出來,作為RFC2198中定義的冗餘編碼(redundantencoding)。除了FEC之外,還可以向包中加入額外的冗餘編碼,但這些資訊 不受FEC的保護。
    主編碼(primarycodec)的冗餘編碼頭(redundantencodingsheader)按照RFC2198中的定義進行設定。下面給出 FEC資料的冗餘編碼頭的設定。塊荷載型別域(blockPT)設定為與FEC格式相關聯的動態PT值,塊長度設定為FEC頭和FEC荷載的長度之和。時 間戳偏移(timestampoffset)應當設定為0。次編碼(secondarycodec)的荷載包括FEC頭和FEC荷載。
    在接收端,主編碼和所有的次編碼都作為不同的RTP包提取出來。這是通過把冗餘編碼包中的RTP頭的次序號、SSRC、標記位、CC域、RTP版本號和擴 展位等拷貝到每一個提取出的包的RTP頭中去。如果次編碼中包含FEC,FEC包的RTP頭中的CC域、擴充套件位、填充位都必須設定為零。提取出的包的荷載 型別碼是從冗餘編碼頭中的塊荷載型別域複製過來。提取出的包的時間戳是RTP頭中的時間戳與塊頭中的時間戳偏移之差。提取包的荷載就是塊中的資料部分。這 樣一來,FEC流和媒體資料流就被分別提取出來了。
要利用FEC包和已接收到的媒體資料包來恢復丟失的包,必須把媒體資料包中的CSRC列表、擴充套件頭、填充部分去掉,並把CC域,擴充套件位、填充位都設定為 零。用這些修改之後的媒體包,加上FEC包,基於第8節中的步驟,就可以恢復出丟失的包。恢復出的包將肯定沒有擴充套件部分、填充部分和CSRC列表部分。在 具體實現中,如果其它包中存在這些部分,可以從其它包中將這些部分拷貝過來。
    使用冗餘編碼的荷載格式,有可能不能正確恢復出標記位。在使用RFC2198來進行FEC封裝的應用程式中,必須把恢復出的媒體資料包的標記位設定為零。相對於傳送完整的FEC包,這種方法的優點在於它能夠減少overhead。

11    在SDP中表示FEC
    FEC包的RTP荷載型別值是一個動態型別值。FEC包可以發到與媒體包不同的多播組或者不同的埠。如果使用[5]中定義的冗餘編碼荷載格式,FEC數 據甚至可以放在媒體包中一起傳輸。這些配置選項必須在帶外明確指示出來。這一節講述如何用RFC2327[6]中定義的會話描述協議 (SessionDescriptionProtocol,SDP)來完成這一工作。

11.1    FEC作為獨立的流傳輸
    在第一種情況中,FEC包是作為一個獨立的流來進行傳輸的。這可能意味著它們被髮往與媒體包不同的埠或不同的多播組。這時,必須傳達以下幾條訊息:
oFEC包被髮往的地址和埠
oFEC包的荷載型別號
o它保護的是哪個媒體資料流
    FEC的荷載型別號是在它所保護的媒體的m行(譯者注:媒體描述行,mediadescription line,見RFC2327)中傳送的。由於沒有為FEC分配靜態的荷載型別值,因此必須使用動態的荷載型別值。這個值的繫結是通過一個rtpmap屬性 來指示的,繫結中所使用的名稱為"parityfec"。
FEC的荷載型別號出現在它所保護的媒體的m行中並不意味著FEC包要傳送到相同的地址和埠。事實上,FEC包的埠和地址資訊是通過fmtp屬性行來傳遞的。在媒體的m行中出現FEC荷載型別指示為了指出FEC保護的是哪個媒體流。
FEC的fmtp行的格式如下所示:
a=fmtp:<荷載型別號><埠><網路型別><地址型別><連線地址>
其中“荷載型別號”就是在m行中出現的荷載型別號。“埠”是FEC包將要傳送的埠。其餘的三項,網路型別,地址型別和連線地址與SDP的c行中的語法 語義是相同的。這樣fmtp行可以部分地用與c行相同的解析器來進行解析。需要注意的是由於FEC不能夠分級編碼,<地址數量 (numberofaddresses)>引數必須不出現在連線地址中。
下面是一個FEC包的SDP例子:
v=0
o=hamming28908445262890842807INIP4126.16.64.4
s=FECSeminar
c=INIP4224.2.17.12/127
t=00
m=audio49170RTP/AVP078
a=rtpmap:78parityfec/8000
a=fmtp:7849172INIP4224.2.17.12/127
m=video51372RTP/AVP3179
a=rtpmap:79parityfec/8000
a=fmtp:7951372INIP4224.2.17.13/127
    在上面的SDP描述中出現兩個m行是因為其中存在兩個媒體流,一個音訊流和一個視訊流。媒體格式為0代表用PCM編碼的音訊,它被荷載型別號為78的 FEC流保護。FEC流被髮往與音訊相同的多播組,TTL引數也相同,但埠號大2(49172)。視訊流被荷載型別號為79的FEC流保護,這個FEC 流的埠號是一樣的,但是多播地址不一樣。

11.2    在冗餘編碼中使用FEC
    當FEC流以冗餘編碼格式作為一個次編碼來發送的時候,必須通過SDP通知對方。為了做到這一點,使用RFC2198中定義的步驟來通知對方使用了冗餘編 碼。FEC的荷載型別就象其它任意一個次編碼那樣表示出來。必須用一個rtpmap屬性行來指示出FEC包的動態荷載型別號。FEC必須只保護主編碼。這 時,FEC的fmtp屬性必須不出現。
舉個例子:
m=audio12345RTP/AVP12105100
a=rtpmap:121red/8000/1
a=rtpmap:100parityfec/8000
a=fmtp:1210/5/100
    這個SDP例子指示有一個單一的音訊流,由PCM格式(媒體格式0)和DVI格式(媒體格式5)組成,一個冗餘編碼(用媒體格式121表示,在 rtpmap屬性中繫結為red),以及一個FEC(媒體格式100,在rtpmap屬性中繫結為parityfec)。儘管FEC格式是作為媒體流的一 個可能編碼來描述的,但它必須不單獨傳送。它出現在m行中只是因為按照RFC2198,非主編碼(non-primarycodec)都必須在這裡列出 來。fmtp屬性指出冗餘編碼格式可以這樣使用:DVI作為一個次編碼(secondarycoding),而FEC作為第三編碼 (tertiaryencoding)。

11.3    在RTSP中的用法
    RTSP[7]可以用來請求將FEC包作為一個獨立的流進行傳輸。當在RTSP中使用SDP時,每個流的會話描述中並不包含連線地址和埠號。作為代替,RTSP使用了控制URL(Control URL)的概念。SDP中以兩種不同的方式來使用控制URL。
1.所有的流使用一個控制URL。這被稱為“集中控制”。在這種情況下,FEC流的fmtp行被省略了。
2.每一個流都有一個控制URL。這被稱為“非集中控制”。在這種情況下,FEC流的fmtp行指定它的控制URL。這個URL可以被用在RTSP客戶端的SETUP命令中。
非集中控制的FEC流用RTSP時,它的fmtp行的格式為:
a=fmtp:<荷載型別號><控制URL>
    其中荷載型別號就是出現在m行中的荷載型別號。控制URL就是用於控制這個FEC流的URL。
    需要注意的是控制URL並不一定是一個絕對URL。將一個相對的控制URL轉化為一個絕對的控制URL的規則在RFC2326的C.1.1中給出。

12    安全性問題
    使用FEC對於加密時金鑰的用法和更改有一定的影響。由於FEC包組成了一個獨立的流,在加密的用法上可以有幾種不同的排列組合:
o可以對FEC流加密,而不對媒體流加密
o可以對媒體流加密,而不對FEC流加密
o可以對媒體流和FEC流同時加密,但使用不同的金鑰
o可以對媒體流和FEC流同時加密,但使用相同的金鑰
    前面三種要求應用層的信令協議知道使用了FEC,並因此對媒體流和FEC流分別進行用法協商,並分別交換金鑰。在最後一種情況裡,並不需要有這些機制,只 要想對待媒體包一樣去對待FEC包就可以了。前面兩種情況可能會引起分層衝突,因為實際上不應該將FEC包與其它媒體包區別對待,並且只對其中一個流加密 會帶來明文攻擊的危險。出於這些考慮,使用了加密的應用就應當對兩個流都進行加密。
    然而,在金鑰的變更中會出現一些問題。例如,如果傳送了兩個資料包a和b,還有一個FEC包f(a,b)。如果a和b所使用的金鑰是不同的,那麼應該用哪一個金鑰來解密f(a,b)?

一般說來,用過的金鑰都會被快取起來,這樣當媒體流的金鑰更改之後,舊的金鑰被保留下來備用,直到它發現FEC包的金鑰也發生更改了。
使用FEC的另一個問題是它對於網路擁塞的影響。面對網路丟包越來越多的情況加入FEC不是一個好辦法,它可能會導致擁塞更加嚴重並最終崩潰。因此,實現者在網路丟包增加的情況下必須不大量增加FEC冗餘資料,以保證整個網路的效能。

13    致謝
    這份方案是基於Budge和Mackenzie於1997年提交的一個早期FEC草案,在此表示感謝。我們感謝 SteveCasner,MarkHandley,OrionHodson和ColinPerkins對我們工作所提出的批評和建議,並感謝 AndersKlemets寫了“在RTSP中的用法”這一節。

14    作者地址
JonathanRosenberg
dynamicsoft
200ExecutiveDrive
Suite120
WestOrange,NJ07046
Email:[email protected]

HenningSchulzrinne
ColumbiaUniversity
M/S0401,1214AmsterdamAve.
NewYork,NY10027-7003
EMail:[email protected]

15    參考書目
[1]J.C.BolotandA.V.Garcia,"Control mechanisms for packet audio in the internet," in Proceeding soft he Conference on Computer Communications(IEEE Info com),(San Francisco, California),Mar.1996.
[2]Perkins,C.andO.Hodson,"Options for Repair of Streaming media",RFC2354,June1998.
[3]Schulzrinne,H.,Casner,S.,Frederick,R.andV.Jacobson,"RTP:A Transport Protocol for Real-Time Applications",RFC1889, January1996.
[4]Bradner,S.,"Keywords for use in RFCs to indicate requirement levels",BCP14,RFC2119,March1997.
[5]Perkins,C.,Kouvelas,I.,Hodson,O.,Hardman, V.,Handley,M., Bolot,J.C., Vega-Garcia, A.andS.Fosse-Parisis,"RTP Payload for Redundant Audio Data",RFC2198,September1997.
[6]Handley,M.andV.Jacobson,"SDP:SessionDescriptionProtocol",RFC2327,April1998.
[7]Schulzrinne,H.,Rao,A.andR.Lanphier,"RealTimeStreamingProtocol(RTSP)",RFC2326,April1998.


    版權歸Internet協會所有(1999)。保留所有權利。
    本文及其譯本可以提供給其他任何人,可以準備繼續進行註釋,可以繼續拷貝、出版、釋出,無論是全部還是部分,沒有任何形式的限制,不過要在所有這樣的拷貝 和後續工作中提供上述宣告和本段文字。無論如何,本文件本身不可以做任何的修改,比如刪除版權宣告或是關於Internet協會、其他的Internet 組織的參考資料等。除了是為了開發Internet標準的需要,或是需要把它翻譯成除英語外的其他語言的時候,在這種情況下,在Internet標準程式 中的版權定義必須被附加其中。
    上面提到的有限授權允許永遠不會被Internet協會或它的繼承者或它的下屬機構廢除。
    本文件和包含在其中的資訊以"Asis"提供給讀者,Internet社群和Internet工程任務組不做任何擔保、解釋和暗示,包括該資訊使用不破壞任何權利或者任何可商用性擔保或特定目的。

(JonathanRosenberg)

相關推薦

rfc 5109 錯碼(FEC)的RTP荷載格式

TAG: 本備忘錄狀態    本文件講述了一種Internet通訊的標準Internet跟蹤協議,並對其改進提出了討論和建議。請參考最新版本的"Internet Official Protocol Standards"(STD1)來獲得本協議的標準化程序和狀態,此備忘錄的釋出不受任何限制。版權注意    版權

錯碼(FEC)的RTP荷載格式

redundant 概念 連接 方法 編碼方式 表示 pmap cut ecan http://www.rosoo.net/a/201110/15146.html本文檔規定了一般性的前向糾錯的媒體數據流的RTP打包格式。這種格式針對基於異或操作的FEC算法進行了特殊設計,它

引用

rac recent har 函數調用 file back 前向引用 lin error: 函數定義 在 函數調用 之前 而函數定義的順序無關緊要 就如同變量的定義一般 a = 1 b = 2 #兩者沒什麽不同 b = 2 a = 1   例 def bbb()

隱馬爾科夫模型HMM(二)算法評估觀察序列概率

流程 來看 遞推 limits its 可能 基本 通過 如何     隱馬爾科夫模型HMM(一)HMM模型     隱馬爾科夫模型HMM(二)前向後向算法評估觀察序列概率     隱馬爾科夫模型HMM(三)鮑姆-韋爾奇算法求解HMM參數(TODO)     隱馬爾科夫模型

UESTC30-最短路-Floyd最短路、spfa+鏈式星建圖

ring 輸入 sam -m 努力 成都 edge 輸出 工作 最短路 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) 在每年的校賽裏,所有進入決

鏈式

前向星 span 鏈式前向星 pan ont 學會 family style mil 鏈式前向星 鏈式前向星 鏈式前向星 重要的事情說三遍 明天不學會鏈式前向星我絕食三天鏈式前向星

淺談

net inf 存在 then 停止 換上 sizeof col idt 現在才搞懂前向星的遍歷,原來是要從後往前的!之後的一切都是以此為基礎的。 1.前向星的遍歷 看到有一篇blog寫的不錯:http://blog.csdn.net/acdreamers/article/

深度理解鏈式星——轉載自ACdreamer

show padding dream idt 特殊 邊集數組 == 影響 mbo // ‘ + obj.name + " "; html += ‘ ‘; html

HMM條件下的 算法 和 維特比解碼

popu max trac ble -s 序列 最大 可能 content 一、隱馬爾科夫HMM如果: 有且僅僅有3種天氣:0晴天。1陰天。2雨天 各種天氣間的隔天轉化概率mp: mp[3][3] 晴天 陰天 雨天

1個TensorFlow樣例,終於明白如何實現傳播過程?

tensorflow神經網絡的結構,就是不同神經元間的連接結構–圖示了一個三層全連接神經網絡。神經元結構的輸出,是所有輸入的加權、加上偏置項,再經過一個激活(傳遞)函數得到。全連接神經網絡全連接神經網絡,就是相鄰兩層之間,任意兩個節點之間都有連接。–這也是其與後面介紹的卷積層、LSTM結構的區分。–除了輸入層

【模板】星 SPFA求最短(長)路

代碼 poj ostream name 兩個 col spfa ron esp 之前一個改自別人的模板竟然在一道題上TLE了,而代碼也實在醜陋,網上找得到的模板也大多跑得慢(vector存圖)或代碼醜陋、殘疾(無初始化函數的模板能叫模板嗎?),索性自己重新寫了一個。 題是P

模板-星的vector實現

code names end 模板 n) node color span col   之前用慣了指針型的前向星,每一次都得手打20行代碼,十分不爽。之後學了vector,腰不酸了,腿不疼了,寫代碼也方便多了。 1 //前向星模板 2 #include <cstd

模板-深度優先搜索的星實現

log from using struct code als max cnblogs 說了   最近學了前向星,非常爽,什麽都想重新寫一遍,哈哈哈......   不說了,先拿dfs開刀。 1 #include <cstdio> 2 #include &l

算法筆記--圖的存儲之鏈式

算法筆記 div soft 鏈式前向星 target href 圖的存儲 blank 所有 鏈式前向星 這個博客寫的不錯:http://www.cnblogs.com/Tovi/p/6194786.html 模板: ①add_edge void add_e

最短路 spfa 算法 && 鏈式星存圖

.com mem ont .aspx 百度 dfs edit 時間復雜度 tails 推薦博客 https://i.cnblogs.com/EditPosts.aspx?opt=1      http://blog.csdn.net/mcdonnell_douglas/

POJ 3159 Candies(差分約束+spfa+鏈式星)

void tdi div con pre ace != view ash 題目鏈接:http://poj.org/problem?id=3159 題目大意:給n個人派糖果,給出m組數據,每組數據包含A,B,C三個數,意思是A的糖果數比B少的個數不多於C,即B的糖果數 -

算法Python實現

基本 是什麽 比較 down 第一天 什麽 可能性 馬爾可夫模型 完全 前言 這裏的前向算法與神經網絡裏的前向傳播算法沒有任何聯系。。。這裏的前向算法是自然語言處理領域隱馬爾可夫模型第一個基本問題的算法。 前向算法是什麽? 這裏用一個海藻的例子來描述前向算法是什麽。網上有關

caffe中的傳播和反向傳播

sla hit img 部分 可能 說明 caff .com 容易 caffe中的網絡結構是一層連著一層的,在相鄰的兩層中,可以認為前一層的輸出就是後一層的輸入,可以等效成如下的模型 可以認為輸出top中的每個元素都是輸出bottom中所有元素的函數。如果兩個神經元之間沒

卷積層,池化層等,/反向傳播原理講解

簡單 代碼 構建 range expand 使用場景 神經網絡 右下角 body 今天閑來無事,考慮到以前都沒有好好研究過卷積層、池化層等等的前向/反向傳播的原理,所以今天就研究了一下,參考了一篇微信好文,講解如下: 參考鏈接:https://www.zybuluo.co

引用筆記

rom AS 缺少 報錯 clas print 前向引用 col pre # 用例一 #缺少調用的函數會報錯 # def foo(): # print("from foo") # bar() # # foo() # 用例二 # def bar(): #