本備忘錄狀態
本文檔講述了一種Internet通信的標準Internet跟蹤協議,并對其改進提出了討論和建
議。請參考最新版本的"InternetOfficialProtocolStandards"(STD1)來獲得本協議的
標準化進程和狀態,此備忘錄的發布不受任何限制。
版權注意
版權歸因特網協會(1998)所有,保留一切權利。
摘要
本文檔描述了針對JPEG視頻流的RTP荷載格式。此種包格式針對編碼器參數基本不變化
的實時視頻流進行了優化。
本文檔是IETF下的視音頻傳輸工作組的產品。意見或建議請發到該工作組的郵件列表
conf@es.net或直接發給作者。
本備忘錄的大部分與RFC2035一致,對協議的改動見附錄D。
目錄
1.簡介 3
2.術語 3
3.RTP上的JPEG 4
4.RTP/JPEG包格式 4
4.1JPEG頭 4
4.1.1類型特定:8比特 5
4.1.2分段偏移:24比特 5
3.1.3類型:8比特 5
3.1.4Q:8比特 5
3.1.5寬度:8比特 5
3.1.6高度:8比特 5
3.1.7復位標記頭 6
3.1.8量化表頭 6
3.1.9JPEG荷載 7
4.討論 7
4.1類型域 7
4.2Q域 8
4.3分片和組裝 9
4.4復位標記 9
5.安全性問題 9
原文作者地址 10
參考文獻 11
附錄A 12
附錄B 13
附錄C 18
附錄D 22
版權聲明 23
1.簡介
聯合圖像專家組(JPEG)標準[1,2,3]定義了一組針對連續色調靜止圖像的壓縮算法。這
個靜止圖像壓縮算法同樣也可以應用于視頻壓縮,把每一幀都當作一個獨立的靜態圖像來進
行壓縮,然后再按次序進行傳輸。這樣一種視頻編碼通常被稱作運動JPEG(Motion-JPEG)。
我們首先介紹JPEG的概況,然后描述RTP所支持的JPEG的子集,以及將JPEG幀通過
RTP包來傳輸的機制。
JPEG標準定義了四種操作模式:順序DCT模式,漸進DCT模式,無損模式,以及分級模
式。在不同的模式下,一幅圖像用一個或多個“節”來表示,每一節(在JPEG標準中稱為一
幀)又進一步分成若干次掃描。在每一次掃描中,有一種到四種分量,這些分量代表著彩色
信號的分量(例如“紅綠藍”或一個亮度分量和兩個色差分量)。這些分量可以分開在不同
的掃描中編碼,也可以交織在一次單一的掃描中。
每一幀或每一次掃描前面都有一個頭,可選的壓縮參數定義,例如量化表和哈夫曼編碼
表。頭信息、可選參數以及一個定位符構成了一個頭區段。每一個掃描都是一個經過熵編碼
的比特流,位于兩個頭區段之間。定位符是字節對齊的,并且不能在熵編碼部分出現,這樣
對于掃描邊界的確定就無需解析整個碼流。
壓縮數據有三種表示格式:交換格式、緊縮格式和表格描述格式。交換格式包含在熵編
碼過程中用到的所有碼表的定義,緊縮模式中省略了一些碼表定義,假定他們在外部定義或
在前面的圖像中定義。
JPEG標準并不關心組成圖像的各個分量的含義或格式。諸如色彩空間和象素縱橫比這些
屬性在JPEG碼流的外部來定義。JPEG文件交換格式(JFIF)在應用標記段(APPO)提供這
些額外信息,它是一個事實上的標準。簡單說來,JFIF文件就是一個JPEG碼流加上一個APPO
段。對于視頻來說,另外還有一些參數在外部定義,比如幀率,逐行掃描還是隔行掃描等等。
盡管JPEG提供了一整套用于靈活壓縮的算法,但是目前能夠實現整套標準的低成本硬件
還沒出現。事實上,絕大部分JPEG硬件編解碼器都只實現了其中的一個子集,也就是順序
DCT模式。典型的做法是,頭區段信息由軟件來解碼,而用硬件來處理一個在YUV色彩空間
中表示的經過熵編碼的單一的掃描。
一次掃描中包含了一系列最小編碼單元(MCU),每個MCU定義了輸出圖像的一個小矩形
快的數據。
JPEG數據中的復位標記表示解碼器應當在當前點復位它的狀態。如JPEG中定義的那樣,
復位標記是唯一的能夠嵌入在熵編碼碼流里的標記,但他們只能夠在MCU的邊界處出現。一
個復位間隔是指兩個復位標記之間的數據部分。每一幀的第一個復位間隔是一個例外,它們
前面沒有復位標記。當使用這些標記時,每一幀都由固定數目的復位間隔組成。
2.術語
本文檔中出現的關鍵字“必須”,“必須不”,“要求的”,“應該”,“不應該”,“會”,“不
會”,“建議”,“或許”,“可選的”按照RFC2119[9]中的描述進行解釋。
3.RTP上的JPEG
為了最大化硬件編解碼器的互操作性,我們假定使用順序DCT模式[1,附錄F],并且限
制預定義的RTP/JPEG類型碼為單一掃描的隔行圖像。這甚至比基本JPEG更為嚴格,很多硬
件實現都不能正確解碼基本JPEG(例如,很多硬件不能解碼逐行掃描)。
實際上,在一個視頻碼流中,大部分表格描述的數據在一個視頻碼流中很少發生變化,
這樣在省略掉所有可以省掉的表格之后,RTP/JPEG數據就可以用緊縮格式來表示了。每一幀
一開始是一個熵編碼的掃描。同時存在于幀頭和掃描頭中的信息都在RTP/JPEG頭中表示,
RTP/JPEG頭位于RTP頭和JPEG荷載之間。
類似于哈夫曼碼表和色彩空間這樣的參數在整個視頻流的生命期中都保持不變,然而另
一些參數則是可以變化的,例如量化表和圖像大?。榱藢崿F自適應碼率傳輸,允許用戶手
工調節量化等級或分辨率)。因此RTP/JPEG頭中分配了專門的數據域來表示這些信息。因為
量化表中只有一個小子集是經常使用的,我們用一個短整數來表示整個量化表集。一些特定
范圍的值表示使用自定義的量化表,這種情況下量化表位于JPEG荷載之前。圖像的寬和高是
顯式編碼的。
因為一個JPEG幀一般總比網絡的最大包長要大,它必須被切分成若干個包。一種方法是
在RTP下面的網絡層來進行分片。但是,這種方法使得對于最終數據包流的碼流控制及有丟
包情況下的部分發送成為不可能,而且幀長有可能超過網絡層的最大組裝長度(詳細信息參
考[10])。為了克服這些問題,RTP/JPEG在RTP層定義了一個簡單的分片/組裝方案。
4.RTP/JPEG包格式
RTP的時間戳是以90000Hz采樣的,同一幀的每一個包都必須有同樣的時間戳。一幀的
最后一個包的RTP標志位必須為1。
4.1JPEG頭
每一個包的RTP頭之后都緊跟著一個JPEG頭。這個頭的前8個字節,稱作“主JPEG頭”,
定義如下:
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|類型特定|分段偏移|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|類型|Q|寬|高|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
同一個JPEG幀的的各個包的所有數據域,除了“分段偏移”之外,都必須保持一致。
這個頭之后可能會跟著一個復位頭和/或量化表頭,這取決于“類型”域和“量化”域的
值。
4.1.1類型特定:8比特
這個數據域的含義取決于“類型”域的值。如果沒有指定,這個域必須為0并且被接收
端忽略。
4.1.2分段偏移:24比特
分段偏移是當前包在整個JPEG幀中的偏移位置,以字節為單位,以網絡字節次序編碼(最
重要位在前)。分段偏移加上當前包中的荷載數據長度不能超出2^24字節。
3.1.3類型:8比特
類型域給出了可能出現在JPEG緊縮格式表格描述或JPEG未定義的JFIF風格參數的信
息。類型0-63在本文檔或本文檔將來的修改中定義,類型64-127與類型0-63相同,除
了在主JPEG頭后緊跟一個復位標記頭,并且在JPEG數據中存在復位標記。類型128-255
可以通過一個會話建立協議來動態定義(這不在本文檔的討論范圍之內)。
3.1.4Q:8比特
Q域定義了當前幀的量化表。Q值為0-127時量化表可以通過類型域決定的一個參數來
計算出來(具體計算方法見后)。Q值為128-255時會有一個量化表頭出現在當前幀第一個
包的主JPEG頭之后。這個量化表頭用來明確定義量化表。
3.1.5寬度:8比特
寬度域編碼圖像的寬度,以8象素為單位(例如,寬度為40表示圖像寬度為320象素)。
最大寬度為2040象素。
3.1.6高度:8比特
高度域編碼圖像的高度,以8象素為單位(例如,高度為30表示圖像高度為240象素)。
當編碼交織視頻時,這里表示的是一個視頻場的高度,因為每個場是單獨編碼的。最大高度
是2040象素。
3.1.7復位標記頭
在類型64-127時,復位標記必須緊跟在主JPEG頭之后。它提供了正確解碼一個包含復
位標記的數據流所需要的額外信息。
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|復位間隔|F|L|復位計數|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
復位間隔域給出了兩個復位標記之間MCU的數目。它和JFIF頭中DRI標記段的16比特
值是一致的。這個值不能為零。
如果一幀中的復位間隔不能保證在包邊界處對齊,F比特和L比特必須設為1,復位計數
必須設為0x3fff。這樣接收端就必須在解碼之前首先重新組裝整個幀。
為了支持部分幀解碼,必須把一幀分成若干塊,每一塊包含整數個復位間隔。復位計數
域給出第一個復位間隔在當前塊中的位置,從而接收端可以知道這些數據對應于當前幀的哪
個部分。復位間隔長度的選取應能夠使一個塊完全放進一個包中。在這種情況下,F比特和L
比特都必須設為1。然而,如果一個塊要放在多個包里,只有第一個包的F比特設為1,也只
有最后一個包的L比特設為1。
3.1.8量化表頭
Q值為128-255時,量化表頭必須出現在主JPEG頭之后(如果存在復位標記頭,則位
于復位標記頭之后)。它提供了一種在帶內描述與Q值對應的量化表的方法。
0123
01234567890123456789012345678901
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|MBZ|精度|長度|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|量化表數據|
|...|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
長度域給出了后面量化表數據的長度,以字節為單位。長度域為零表示當前幀沒有量化表
數據。詳細信息參考4.2。如果長度域的值比剩余的字節數大,整個包必須丟棄。
包含量化表數據時,表的個數取決于JPEG類型域的值。例如。類型0使用兩個表(一個
用于亮度分量,另一個用于色差分量)。每個表是一個64個值得數組,按zig-zag次序,與
JFIF的DQT標記段一致。
對于每一個量化表,精度域的一個比特指示了表中系數的大小。如果這個比特為0,系數
為8比特,表長度為64個字節。如果該比特為1,系數就是16比特的,表長度為128字節。
對于16比特的表系數,字節次序是網絡次序。精度域的最右邊的比特對應于第一個表,后面
的表依次對應于左邊的下一個比特。超出表個數的那些比特必須被忽略。
對于Q值為128-254的情況,Q值與量化表之間的映射必須是靜態的,也就是說,保證
接收端只需要讀一次與某個Q值對應的量化表,就可以正確解碼出所有用該Q值編碼的幀。
解碼器不能依賴于任何以前的量化表,而需要在每幀都重新載入這些量化表。Q=255并且長
度為0的包是不允許的。
3.1.9JPEG荷載
緊跟RTP/JPEG頭的數據是包含一次掃描的熵編碼的圖像數據。這次掃描不包含掃描頭,
掃描頭的信息可以從RTP/JPEG頭中推出。掃描的結束可能是隱含的(整幅圖象都已經完全解
碼),也可能是顯式的,即跟著一個EOI標記。一次掃描可能會用一些未定義字節填充到任
意長度(一些現存的硬件編解碼器會在一幀圖象的底部生成一些額外的行,解碼器需要對它
們進行哈夫曼解碼來去除這些額外的行。
類型碼決定著復位標記是否存在。如果某種類型支持復位標記,數據包的復位頭中必須
包含一個非零的復位間隔值,并且復位標記必須是字節對齊的,以一個0xFF起始。另外的
0xFF字節可以出現在復位間隔之中。在打包過程中,用這樣的方法來進行對齊,例如字對齊,
從而實現比較高效的拷貝。除此之外,復位標記不能出現在碼流中的任何其它地方。不支持
復位標記的類型的碼流在任何地方都不能包含復位標記。在數據包中,如果熵編碼產生了一
個0xFF字節,則必須在它后面填充一個0x00字節。[見文獻1的B.1.1.5]
4.討論
4.1類型域
類型域定義了緊縮的表格描述和JPEG中未定義的額外的JFIF風格參數,因為這些信息
在待傳輸的JPEG數據中不存在。
類型域定義了三種取值范圍。0-63的含義是固定的,在本文檔或本文檔的將來版本中
定義。64-127與0-63的區別僅在于包含復位標記,并且在主JPEG頭后緊跟著一個復位頭,
其余都完全一致。128-255是可以由一個會話建立協議來動態定義的(這不再本文的討論范
圍之內)。
對于第一類取值范圍,類型0和類型1目前已經定義了,對應第二類范圍中的類型64和
類型65。類型0,1指的是基本DCT順序模式、8比特采樣、正方形象素、YUV三種顏色分量
以及標準哈夫曼碼表[在文獻1的附錄K.3中定義],一次隔行掃描并帶一個掃描分量選擇子,
來指示是分量1,2還是3。Y,U和V分量分別對應于分量1,2,3。分量1使用0號哈夫曼
碼表和0號量化表,分量2和3使用1號哈夫曼碼表和1號量化表。
類型碼2-5定為保留,并禁止使用?;诒疚臋n以前版本(RFC2035)的應用應當更新
對于類型64和類型65的解釋,指示出有復位標記的存在。
這兩種RTP/JPEG類型當前的具體定義如下:
類型分量水平采樣因子.垂直采樣因子量化表序號
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||1(Y)|2|1|0|
|0,64|2(U)|1|1|1|
||3(V)|1|1|1|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
||1(Y)|2|2|0|
|1,65|2(U)|1|1|1|
||3(V)|1|1|1|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
采樣因子說明類型0的視頻的色度分量水平方向上二倍降采樣(一般稱為4:2:2),
而類型1的視頻的色度分量在水平和垂直兩個方向上都二倍降采樣(一般稱為4:2:0)。
類型0和類型1既可以用于傳輸漸進掃描的圖象數據,也可以用于傳輸隔行掃描的圖象
數據。這兩種不同的數據格式在主JPEG頭中加以區分。具體定義如下:
0:圖象是漸進掃描的。在計算機顯示器上,它可以按照制定的大小來顯示。
1:當前圖像是隔行掃描視頻信號的奇數場。主JPEG頭中給出的高度是整個圖象高度的
一半。當前場應當與后面緊跟的偶數場一起重新恢復出整幀圖象。偶數場的行恰好處
于奇數場對應行的上方。
2:當前圖象是隔行掃描視頻信號的偶數場。
3:當前圖象是隔行掃描視頻信號的一場,但它將按整幀圖象的大小來單獨顯示。在計算
機顯示器上,每一行都顯示兩遍,圖象高度加倍。
附錄B中給出了將RTP/JPEG頭中的信息變換到JPEG幀頭和掃描頭的C源碼。
4.2Q域
對于JPEG類型0和類型1(以及相應的類型64和65),Q值1-99的定義如下。其它
128以下的值保留。
類型0和類型1都需要有兩個量化表。這些量化表的計算方法如下:對于1<=Q<=99,
用JPEG組織的公式[5]來計算一個標量量化因子S:
S=5000/Q如果1<=Q<=50
=200-2*Q如果51<=Q<=99
然后把這個S值代入[1]中的表K.1和K.2(每個值都擴展到8比特),就分別得到了量
化表0和量化表1。計算量化表的C源碼在附錄A中給出。
當Q值在128-255之間時,就需要使用動態定義的量化表。這些量化表既可以在帶內定
義,也可以在帶外通過一個會話建立協議來定義。但在每一幀的第一個包中必須有一個量化
表頭。當量化表在帶外定義時,可以通過將包頭中的長度域設為0來省略掉量化表。
當在帶內傳輸量化表時,并不需要在每一幀都重復傳送一遍。類似于帶外的情況,不包
含量化表的幀可以在包頭中將長度域設置為0。盡管這樣做減小了傳輸量化表帶來的
OVERHEAD,但是也帶來了一些負面效應。一個新的接收者在收到完整量化表之前接收到的所
有幀都不能夠正確解碼。
4.3分片和組裝
由于JPEG的每一幀都相當大,必須經過切分才便于傳輸。在將一幀切分成若干個包的過
程中,應當避免在低層進行分片。如果要求支持部分幀解碼,被切分出的每一個包就應當包
含整數個復位間隔(如下)。組成同一幀的數據包的時間戳必須保持一致,并且最后一個包
的RTP標記位必須為1。每個包的分段偏移域的值是這個包中數據在原來整個幀中的偏移位
置,以字節為單位。這些包必須按照次序進行傳輸,并且它們所包含的圖象數據不能重疊。
整個一幀圖象以一個分段偏移為0的包為起始,并以一個RTP標記位為1的包為結束???br/>
以通過RTP的順序號或者分段偏移結合每個包的長度來檢測丟包。數據的重組可以不使用分
段偏移的數據(只使用RTP標記位和RTP順序號),但是在出現包的亂序的情況下,就不可
能通過簡單的拷貝操作來實現圖象數據的重組。而且,如果前一幀的最后一個包丟失的話,
即使當前幀完好無損,接收段也不能夠正?;謴统霎斍皫?。
4.4復位標記
復位標記插入在JPEG碼流中,告訴接收端哈夫曼解碼器和直流預測器應當在當前位置復
位,并且允許從當前點開始進行部分解碼。然而,為了充分實現部分解碼,解碼器必須知道
一個復位間隔中包含的是哪些MCU。為此,原來的JPEG標準中在復位標記中提供了一個短的
次序號域。但是對于典型的網絡MTU長度來說,這個數域不夠長,不能很好的處理丟包問題。
因此,在RTP/JPEG的復位頭中包含了額外的信息來處理這個問題。
復位間隔的大小應當使得整數個復位間隔能夠恰好放在一個數據包里。這樣就可以保證
這些包可以相互獨立地進行解碼。如果一個復位間隔的結束處超出了一個包的長度,可以使
用復位標記頭中的F比特和L比特來對它進行切分。但是這樣生成的包的集合必須全部接收
到,接收端才可以正確解碼出那個復位間隔中的數據。
一旦解碼器接收到一個F和L都為1的包,或者是一連串的包,第一個F為1,最后一
個L為1,它就可以開始解碼了。起始MCU在整幅圖象中的位置可以通過將復位計數的值與
復位間隔的值相乘來確定。這樣的一個包(或一連串包)可以包含任意數量的連續的復位間
隔。
為了兼容生成碼流中就包含復位標記但無法按這些復位標記來分片的編碼器,將復位計
數域設為0x3FFF并且F和L均為1。這樣一種模式意味著解碼器必須對整幅圖象首先進行重
組,然后才能解碼。
5.安全性問題
本文檔中所定義的RTP包格式的安全性問題可以遵循[6]和[7]中的建議。這意味著媒體
數據流的安全性是通過加密來實現的。因為對于媒體數據的壓縮是端到端的,加密操作可以
在壓縮操作之后執行,這樣在兩種操作之間就不存在任何沖突。
對于解碼端計算量不均衡的壓縮編碼計數,存在一種潛在的拒絕服務的攻擊威脅。攻擊
者可以在數據流中插入一些惡意的數據包,對于這些包的解碼會導致解碼器運算量過載。幸
運的是,我們的壓縮編碼算法并沒有明顯的計算量不均衡現象。
另一種潛在的拒絕服務威脅存在于我們提出的分片重組機制。接收端應當限制重組數據
的總長,以避免資源耗盡。
對于任何基于IP的協議,接收端在某些情況下可能會因為接收到過多的數據包而發生過
載。網絡層的鑒定機制可以將來自不明來源或惡意來源的數據包丟棄,但是這樣做所帶來的
成本也是相當高的。在組播的環境里,刪除某些源的數據包可以通過IGMP[8]的未來版本和
組播路由協議來實現,從而允許用戶來選擇哪些數據源是允許的,哪些是不允許的。
對于這種荷載格式的安全性考慮并不超出RTP規范中的內容。
原文作者地址
LanceM.Berc
SystemsResearchCenter
DigitalEquipmentCorporation
130LyttonAve
PaloAltoCA94301
Phone:+16508532100
Email:berc@pa.dec.com
WilliamC.Fenner
XeroxPARC
3333CoyoteHillRoad
PaloAlto,CA94304
Phone:+16508124816
Email:fenner@parc.xerox.com
RonFrederick
XeroxPARC
3333CoyoteHillRoad
PaloAlto,CA94304
Phone:+16508124459
Email:frederick@parc.xerox.com
StevenMcCanne
UniversityofCaliforniaatBerkeley
ElectricalEngineeringandComputerScience
633SodaHall
Berkeley,CA94720
Phone:+15106420865
Email:mclearcase/" target="_blank" >ccanne@cs.berkeley.edu
PaulStewart
XeroxPARC
3333CoyoteHillRoad
PaloAlto,CA94304
Phone:+16508124821
Email:stewart@parc.xerox.com
參考文獻
[1]ISODIS10918-1.DigitalCompressionandCodingofContinuous-
toneStillImages(JPEG),CCITTRecommendationT.81.
[2]WilliamB.Pennebaker,JoanL.Mitchell,JPEG:StillImageData
CompressionStandard,VanNostrandReinhold,1993.
[3]GregoryK.Wallace,TheJPEGSillPictureCompressionStandard,
CommunicationsoftheACM,April1991,Vol34,No.1,pp.31-44.
[4]TheJPEGFileInterchangeFormat.MaintainedbyC-Cube
Microsystems,Inc.,andavailablein
ftp://ftp.uu.net/graphics/jpeg/jfif.ps.gz.
[5]TomLaneet.Al.,TheIndependentJPEGGroupsoftwareJPEG
codec.Sourcecodeavailablein
ftp://ftp.uu.net/graphics/jpeg/jpegsrc.v6a.tar.gz.
[6]Schulzrinne,H.,Casner,S.,Frederick,R.andV.Jacobson,
"RTP:ATransportProtocolforReal-TimeApplications",RFC
1889,January1996.
[7]Schulzrinne,H.,"RTPProfileforAudioandVideoConferences
withMinimalControl",RFC1890,January1996.
[8]Fenner,W.,"InternetGroupManagementProtocolVersion2",RFC
2236,November1997.
[9]Bradner,S.,"KeywordsforuseinRFCstoIndicateRequirement
Levels",BCP14,RFC2119,March1997.
[10]KentC.,andJ.Mogul,"FragmentationConsideredHarmful",
ProceedingsoftheACMSIGCOMM'87WorkshoponFrontiersin
ComputerCommunicationsTechnology,August1987.
附錄A
下面的代碼用來通過一個Q因子值生成一個量化表:
/*
? TableK.1fromJPEGspec.
*/
staticconstintjpeg_luma_quantizer[64]={
16,11,10,16,24,40,51,61,
12,12,14,19,26,58,60,55,
14,13,16,24,40,57,69,56,
14,17,22,29,51,87,80,62,
18,22,37,56,68,109,103,77,
24,35,55,64,81,104,113,92,
49,64,78,87,103,121,120,101,
72,92,95,98,112,100,103,99
};
/*
? TableK.2fromJPEGspec.
*/
staticconstintjpeg_chroma_quantizer[64]={
17,18,24,47,99,99,99,99,
18,21,26,66,99,99,99,99,
24,26,56,99,99,99,99,99,
47,66,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,
99,99,99,99,99,99,99,99,
99,99,99,99,99,99,99,99
};
/*
? CallMakeTableswiththeQfactorandtwou_char[64]returnarrays
*/
void
MakeTables(intq,u_char*lqt,u_char*cqt)
{
intI;
intfactor=q;
if(q<1)factor=1;
if(q>99)factor=99;
if(q<50)
q=5000/factor;
else
q=200–factor*2;
for(I=0;I<64;I++){
intlq=(jpeg_luma_quantizer[I]*q+50)/100;
intcq=(jpeg_chroma_quantizer[I]*q+50)/100;
/*Limitthequantizersto1<=q<=255*/
if(lq<1)lq=1;
elseif(lq>255)lq=255;
lqt[I]=lq;
if(cq<1)cq=1;
elseif(cq>255)cq=255;
cqt[I]=cq;
}
}
附錄B
下面這段代碼用來生成對應于那些RTP/JPEG中不存在的表描述數據的JPEG標記段。
U_charlum_dc_codelens[]={
0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0,
};
u_charlum_dc_symbols[]={
0,1,2,3,4,5,6,7,8,9,10,11,
};
u_charlum_ac_codelens[]={
0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d,
};
u_charlum_ac_symbols[]={
0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,
0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,
0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,
0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,
0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,
0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,
0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,
0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,
0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,
0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,
0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,
0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,
0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,
0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,
0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,
0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,
0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,
0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,
0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
0xf9,0xfa,
};
u_charchm_dc_codelens[]={
0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
};
u_charchm_dc_symbols[]={
0,1,2,3,4,5,6,7,8,9,10,11,
};
u_charchm_ac_codelens[]={
0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77,
};
u_charchm_ac_symbols[]={
0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,
0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,
0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,
0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,
0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,
0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,
0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,
0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,
0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,
0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,
0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,
0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,
0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,
0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,
0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,
0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,
0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,
0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,
0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,
0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,
0xf9,0xfa,
};
u_char*
MakeQuantHeader(u_char*p,u_char*qt,inttableNo)
{
*p++=0xff;
*p++=0xdb;/*DQT*/
*p++=0;/*lengthmsb*/
*p++=67;/*lengthlsb*/
*p++=tableNo;
memcpy(p,qt,64);
return(p+64);
}
u_char*
MakeHuffmanHeader(u_char*p,u_char*codelens,intncodes,
u_char*symbols,intnsymbols,inttableNo,
inttableClass)
{
*p++=0xff;
*p++=0xc4;/*DHT*/
*p++=0;/*lengthmsb*/
*p++=3+ncodes+nsymbols;/*lengthlsb*/
*p++=(tableClass<<4)|tableNo;
memcpy(p,codelens,ncodes);
p+=ncodes;
memcpy(p,symbols,nsymbols);
p+=nsymbols;
return(p);
}
u_char*
MakeDRIHeader(u_char*p,u_shortdri){
*p++=0xff;
*p++=0xdd;/*DRI*/
*p++=0x0;/*lengthmsb*/
*p++=4;/*lengthlsb*/
*p++=dri>>8;/*drimsb*/
*p++=dri&0xff;/*drilsb*/
return(p);
}
/*
? Arguments:
? type,width,height:assuppliedinRTP/JPEGheader
? lqt,cqt:quantizationtablesaseitherderivedfrom
? theQfieldusingMakeTables()orasspecified
? insection4.2.
? dri:restartintervalinMCUs,or0ifnorestarts.
*
? p:pointertoreturnarea
*
? Returnvalue:
? Thelengthofthegeneratedheaders.
*
? Generateaframeandscanheadersthatcanbeprependedtothe
? RTP/JPEGdatapayloadtoproduceaJPEGcompressedimagein
? interchangeformat(exceptforpossibletrailinggarbageand
? absenceofanEOImarkertoterminatethescan).
*/
intMakeHeaders(u_char*p,inttype,intw,inth,u_char*lqt,
u_char*cqt,u_shortdri)
{
u_char*start=p;
/*convertfromblockstopixels*/
w<<=3;
h<<=3;
*p++=0xff;
*p++=0xd8;/*SOI*/
p=MakeQuantHeader(p,lqt,0);
p=MakeQuantHeader(p,cqt,1);
if(dri!=0)
p=MakeDRIHeader(p,dri);
*p++=0xff;
*p++=0xc0;/*SOF*/
*p++=0;/*lengthmsb*/
*p++=17;/*lengthlsb*/
*p++=8;/*8-bitprecision*/
*p++=h>>8;/*heightmsb*/
*p++=h;/*heightlsb*/
*p++=w>>8;/*widthmsb*/
*p++=w;/*wudthlsb*/
*p++=3;/*numberofcomponents*/
*p++=0;/*comp0*/
if(type==0)
*p++=0x21;/*hsamp=2,vsamp=1*/
else
*p++=0x22;/*hsamp=2,vsamp=2*/
*p++=0;/*quanttable0*/
*p++=1;/*comp1*/
*p++=0x11;/*hsamp=1,vsamp=1*/
*p++=1;/*quanttable1*/
*p++=2;/*comp2*/
*p++=0x11;/*hsamp=1,vsamp=1*/
*p++=1;/*quanttable1*/
p=MakeHuffmanHeader(p,lum_dc_codelens,
sizeof(lum_dc_codelens),
lum_dc_symbols,
sizeof(lum_dc_symbols),0,0);
p=MakeHuffmanHeader(p,lum_ac_codelens,
sizeof(lum_ac_codelens),
lum_ac_symbols,
sizeof(lum_ac_symbols),0,1);
p=MakeHuffmanHeader(p,chm_dc_codelens,
sizeof(chm_dc_codelens),
chm_dc_symbols,
sizeof(chm_dc_symbols),1,0);
p=MakeHuffmanHeader(p,chm_ac_codelens,
sizeof(chm_ac_codelens),
chm_ac_symbols,
sizeof(chm_ac_symbols),1,1);
*p++=0xff;
*p++=0xda;/*SOS*/
*p++=0;/*lengthmsb*/
*p++=12;/*lengthlsb*/
*p++=3;/*3components*/
*p++=0;/*comp0*/
*p++=0;/*Successtable0*/
*p++=1;/*comp1*/
*p++=0x11;/*Successtable1*/
*p++=2;/*comp2*/
*p++=0x11;/*Successtable1*/
*p++=0;/*firstDCTcoeff*/
*p++=63;/*lastDCTcoeff*/
*p++=0;/*Successiveapprox.*/
return(p–start);
};
附錄C
下面這段代碼用來闡明RTP/JPEG數據包分片和頭的生成過程。
Forclarityandbrevity,thestructuredefinitionsareonlyvalidfor
32-bitbig-endian(mostsignificantoctetfirst)architectures.Bit
fieldsareassumedtobepackedtightlyinbig-endianbitorder,with
noadditionalpadding.Modificationswouldberequiredtoconstructa
portableimplementation.
/*
? RTPdataheaderfromRFC1889
*/
typedefstruct{
unsignedintversion:2;/*protocolversion*/
unsignedintp:1;/*paddingflag*/
unsignedintx:1;/*headerextensionflag*/
unsignedintcc:4;/*CSRCcount*/
unsignedintm:1;/*markerbit*/
unsignedintpt:7;/*payloadtype*/
u_int16seq;/*sequencenumber*/
u_int32ts;/*timestamp*/
u_int32ssrc;/*synchronizationsource*/
u_int32csrc[1];/*optionalCSRClist*/
}rtp_hdr_t;
#defineRTP_HDR_SZ12
/*ThefollowingdefinitionisfromRFC1890*/
#defineRTP_PT_JPEG26
structjpeghdr{
unsignedinttspec:8;/*type-specificfield*/
unsignedintoff:24;/*fragmentbyteoffset*/
u_int8type;/*idofjpegdecoderparams*/
u_int8q;/*quantizationfactor(ortableid)*/
u_int8width;/*framewidthin8pixelblocks*/
u_int8height;/*frameheightin8pixelblocks*/
};
structjpeghdr_rst{
u_int16dri;
unsignedintf:1;
unsignedintl:1;
unsignedintcount:14;
};
structjpeghdr_qtable{
u_int8mbz;
u_int8precision;
u_int16length;
};
#defineRTP_JPEG_RESTART0x40
/*ProcedureSendFrame:
*
? Arguments:
? start_seq:Thesequencenumberforthefirstpacketofthecurrent
? frame.
? ts:RTPtimestampforthecurrentframe
? ssrc:RTPSSRCvalue
? jpeg_data:HuffmanencodedJPEGscandata
? len:LengthoftheJPEGscandata
? type:ThevaluetheRTP/JPEGtypefieldshouldbesetto
? typespec:ThevaluetheRTP/JPEGtype-specificfieldshouldbeset
? to
? width:ThewidthinpixelsoftheJPEGimage
? height:TheheightinpixelsoftheJPEGimage
? dri:ThenumberofMCUsbetweenrestartmarkers(or0ifthere
? arenorestartmarkersinthedata
? q:TheQfactorofthedata,tobespecifiedusingtheIndependent
? JPEGgroup'salgorithmif1<=q<=99,specifiedexplicitly
? withlqtandcqtifq>=128,orundefinedotherwise.
? lqt:Thequantizationtablefortheluminancechannelifq>=128
? cqt:Thequantizationtableforthechrominancechannelsif
? q>=128
*
? Returnvalue:
? thesequencenumbertobesentforthefirstpacketofthenext
? frame.
*
? Thefollowingareassumedtobedefined:
*
*PACKET_SIZE-Thesizeoftheoutgoingpacket
? send_packet(u_int8*data,intlen)-Sendsthepackettothenetwork
*/
u_int16SendFrame(u_int16start_seq,u_int32ts,u_int32ssrc,
u_int8*jpeg_data,intlen,u_int8type,
u_int8typespec,intwidth,intheight,intdri,
u_int8q,u_int8*lqt,u_int8*cqt){
rtp_hdr_trtphdr;
structjpeghdrjpghdr;
structjpeghdr_rstrsthdr;
structjpeghdr_qtableqtblhdr;
u_int8packet_buf[PACKET_SIZE];
u_int8*ptr;
intbytes_left=len;
intseq=start_seq;
intpkt_len,data_len;
/*InitializeRTPheader
*/
rtphdr.version=2;
rtphdr.p=0;
rtphdr.x=0;
rtphdr.cc=0;
rtphdr.m=0;
rtphdr.pt=RTP_PT_JPEG;
rtphdr.seq=start_seq;
rtphdr.ts=ts;
rtphdr.ssrc=ssrc;
/*InitializeJPEGheader
*/
jpghdr.tspec=typespec;
jpghdr.off=0;
jpghdr.type=type|((dri!=0)?RTP_JPEG_RESTART:0);
jpghdr.q=q;
jpghdr.width=width/8;
jpghdr.height=height/8;
/*InitializeDRIheader
*/
if(dri!=0){
rsthdr.dri=dri;
rsthdr.f=1;/*ThiscodedoesnotalignRis*/
rsthdr.l=1;
rsthdr.count=0x3fff;
}
/*Initializequantizationtableheader
*/
if(q>=128){
qtblhdr.mbz=0;
qtblhdr.precision=0;/*Thiscodeuses8bittablesonly*/
qtblhdr.length=128;/*264-bytetables*/
}
while(bytes_left>0){
ptr=packet_buf+RTP_HDR_SZ;
memcpy(ptr,&jpghdr,sizeof(jpghdr));
ptr+=sizeof(jpghdr);
if(dri!=0){
memcpy(ptr,&rsthdr,sizeof(rsthdr));
ptr+=sizeof(rsthdr);
}
if(q>=128&&jpghdr.off==0){
memcpy(ptr,&qtblhdr,sizeof(qtblhdr));
ptr+=sizeof(qtblhdr);
memcpy(ptr,lqt,64);
ptr+=64;
memcpy(ptr,cqt,64);
ptr+=64;
}
data_len=PACKET_SIZE–(ptr–packet_buf);
if(data_len>=bytes_left){
data_len=bytes_left;
rtphdr.m=1;
}
memcpy(packet_buf,&rtphdr,RTP_HDR_SZ);
memcpy(ptr,jpeg_data+jpghdr.off,data_len);
send_packet(packet_buf,(ptr–packet_buf)+data_len);
jpghdr.off+=data_len;
bytes_left-=data_len;
rtphdr.seq++;
}
returnrtphdr.seq;
}
附錄D
這一部分給出了本文檔相對于RFC2035的改動。這些改動著眼于盡可能保持新版本對于
舊版本的兼容性。事實上,很多已經廢棄的約定仍然能夠在新版中正常地解碼。盡管如此,
我們仍然強烈反對在新版中使用一些舊地約定。
o類型0和類型1現在可以編碼隔行掃描的視頻圖象,用類型特定域中的兩個比特給
出指示即可。參見4.1節。
oJPEG工作組曾經就如何更靈活地描述JPEG量化表發生過爭論。本備忘錄允許通過使
用一個可選地量化表頭來顯式地描述表系數。這些內容在節3.1.8和4.2中討論。
o在RFC2035中,在類型域中描述復位標記的信息,這樣就很難再加入新的類型。并
且,類型特定域用于記錄復位計數,這樣其它的一些類型特定信息就無法編碼。在
本備忘錄中,復位標記的指示移到了類型域中的一個特定比特位,并且加入了可選
頭來編碼一些必要的額外信息,而把類型特定域留出來用于它本來的用途。對于部
分幀解碼的處理提高了碼流的健壯性,能夠對抗一定程度的丟包。詳細信息參見
3.1.7和4.4。
版權聲明
版權歸Internet協會所有(1998)。保留所有權利。
本文及其譯本可以提供給其他任何人,可以準備繼續進行注釋,可以繼續拷貝、出版、發
布,無論是全部還是部分,沒有任何形式的限制,不過要在所有這樣的拷貝和后續工作中提
供上述聲明和本段文字。無論如何,本文檔本身不可以做任何的修改,比如刪除版權聲明或
是關于因特耐特協會、其他的因特耐特組織的參考資料等。除了是為了開發Internet標準的
需要,或是需要把它翻譯成除英語外的其他語言的時候,在這種情況下,在Internet標準程
序中的版權定義必須被附加其中。
上面提到的有限授權允許永遠不會被Internet協會或它的繼承者或它的下屬機構廢除。
本文檔和包含在其中的信息以"Asis"提供給讀者,Internet社區和Internet工程任務
組不做任何擔保、解釋和暗示,包括該信息使用不破壞任何權利或者任何可商用性擔?;蛱?br/>
定目的。