視頻簡單地說就是活動的圖像。保存和描述數字視頻的簡單方法就是記錄和描述連續的一幀幀的靜止圖像。保存靜止圖像的最簡單格式是BMP格式,就是位圖。BMP是未經壓縮的原始圖像保存格式,採用RGB描述。數字視頻流則採用YUV描述。所以播放視頻時,要將YUV格式的數據轉換成RGB格式顯示。至於YUV與RGB如何相互裝換,這裏不詳細介紹,網上有一大堆資料。
一、視頻壓縮
MPEG視頻壓縮編碼後包括三種元素:
I幀(I-frames):幀內壓縮編碼形成的圖像
P幀(P-frames):前向預測幀,以一個P 幀或 I 幀爲預測幀進行編碼
B幀(B-frames):從相鄰(前後均可)的最近的I 幀或 P 幀作雙向預測進行編碼
在MPEG編碼的過程中,部分視頻幀序列壓縮成爲I幀;部分壓縮成P幀;還有部分壓縮成B幀。I幀法是幀內壓縮法,也稱爲“關鍵幀”壓縮法。I幀法是基於離散餘弦變換DCT( Discrete Cosine Transform )的壓縮技術,這種算法與JPEG壓縮算法類似。JPEG壓縮是一種針對靜止的連續色調的圖像壓縮方法,它屬於帖內壓縮。採用I幀壓縮可達到1/6的壓縮比而無明顯的壓縮痕跡。
MPEG標準採用YCbCr(YUV)4::2:2的採樣格式,其含義爲:每個點保存一個 8bit 的亮度值(也就是Y值),每2個點保存一個 Cr(8bit) 和Cb(8bit) 值, 圖像在肉眼中的感覺不會起太大的變化。其編碼的基本方法是在單位時間內,首先採集並壓縮第一幀的圖像爲I幀。然後對於其後的各幀,在對單幀圖像進行有效壓縮的基礎上,只存儲其相對於前後幀發生變化的部分。幀間壓縮的過程中也常間隔採用幀內壓縮法,由於幀內(關鍵幀)的壓縮不基於前一幀,一般每隔15幀設一關鍵幀,這樣可以減少相關前一幀壓縮的誤差積累。MPEG編碼器首先要決定壓縮當前幀爲I幀或P幀或B幀,然後採用相應的算法對其進行壓縮。一個視頻序列經MPEG全編碼壓縮後可能的格式爲:IBBPBBPBBPBBPBBIBBPBBP BBPBBPBBI......
下面說明I幀、P幀以及B幀的特點:
1.I幀:幀內編碼幀
I幀特點:
①它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸。
②解碼時僅用I幀的數據就可重構完整圖像。
③I幀描述了圖像背景和運動主體的詳情。
④I幀不需要參考其他畫面而生成。
⑤I幀是P幀和B幀的參考幀(其質量直接影響到同組中以後各幀的質量)。
⑥I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀。
⑦I幀不需要考慮運動矢量。
⑧I幀所佔數據的信息量比較大。
2. P幀:前向預測編碼幀。
(1)P幀的預測與重構:P幀是以I幀爲參考幀,在I幀中找出P幀“某點”的預測值和運動矢量,取預測差值(對其進行類似JPEG壓縮編碼)和運動矢量(Huffman編碼)一起傳送。在接收端根據運動矢量從I幀中找出P幀“某點”的預測值並與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。
(2)P幀特點
①P幀是I幀後面相隔1~2幀的編碼幀。
②P幀採用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差)。
③解碼時必須將I幀中的預測值與預測誤差求和後才能重構完整的P幀圖像。
④P幀屬於前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀。
⑤P幀可以是其後面P幀的參考幀,也可以是其前後的B幀的參考幀。
⑥由於P幀是參考幀,它可能造成解碼錯誤的擴散。
⑦由於是差值傳送,P幀的壓縮比較高。
3.B幀:雙向預測內插編碼幀。
(1)B幀的預測與重構
B幀以前面的I或P幀和後面的P幀爲參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,並取預測差值和運動矢量傳送。接收端根據運動矢量在兩個參考幀中“找出(算出)”預測值並與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀(不知如何算出)。
2)B幀特點
①B幀是由前面的I或P幀和後面的P幀來進行預測的。
②B幀傳送的是它與前面的I或P幀和後面的P幀之間的預測誤差及運動矢量。
③B幀是雙向預測編碼幀。
④B幀壓縮比最高,因爲它只反映丙參考幀間運動主體的變化情況,預測比較準確。
⑤B幀不是參考幀,不會造成解碼錯誤的擴散。
注:I、B、P各幀是根據壓縮算法的需要,是人爲定義的,它們都是實實在在的物理幀,至於圖像中的哪一幀是I幀,是隨機的,一但確定了I幀,以後的各幀就嚴格按規定順序排列。
二、視頻編碼
上圖爲視頻壓縮編碼的簡單流程。I幀編碼對象是整個幀內數據,P、B幀編碼的對象是預測差值和運動向量,對差值採用JPEG編碼方式,對運動向量可以簡單地用Huffman編碼。P、B編碼方式與I幀編碼方式大同小異,下面以I幀編碼爲例詳細說明之。
I幀採用的是JPEG編碼方式,JPEG編碼集合DPCM編碼、RLE編碼(行程編碼)、熵編碼(Huffman)等編碼方式一體,所以JPEG有很高的壓縮比。
JPEG編碼的流程爲:
8×8的圖象經過DCT變換後,其低頻分量都集中在左上角,高頻分量分佈在右下角(DCT變換實際上是空間域的低通濾波器)。由於該低頻分量包含了圖象的主要信息(如亮度),而高頻與之相比,就不那麼重要了,所以我們可以忽略高頻分量,從而達到壓縮的目的。如何將高頻分量去掉,這就要用到量化,它是產生信息損失的根源。這裏的量化操作,就是將某一個值除以量化表中對應的值。由於量化表左上角的值較小,右上角的值較大,這樣就起到了保持低頻分量,抑制高頻分量的目的。JPEG使用的顏色是YUV格式。Y分量代表了亮度信息,UV分量代表了色差信息。相比而言,Y分量更重要一些。我們可以對Y採用細量化,對UV採用粗量化,可進一步提高壓縮比。所以上面所說的量化表通常有兩張,一張是針對Y的;一張是針對UV的。
上面講了,經過DCT變換後,低頻分量集中在左上角,其中F(0,0)(即第一行第一列元素)代表了直流(DC)係數,即8×8子塊的平均值,要對它單獨編碼。由於兩個相鄰的8×8子塊的DC係數相差很小,所以對它們採用差分編碼DPCM,可以提高壓縮比,也就是說對相鄰的子塊DC係數的差值進行編碼。8×8的其它63個元素是交流(AC)係數,採用行程編碼。這裏出現一個問題:這63個係數應該按照怎麼樣的順序排列?爲了保證低頻分量先出現,高頻分量後出現,以增加行程中連續“0”的個數,這63個元素採用了“之”字型(Zig-Zag)的排列方法,如下圖所示。
行程編碼
上面,我們得到了DC碼字和 AC行程碼字。爲了進一步提高壓縮比,需要對其再進行熵編碼,這裏選用Huffman編碼,分成兩步:
(1)熵編碼的中間格式表示
對於AC係數,有兩個符號。符號1爲行程和尺寸,即上面的(RunLength,Size)。(0,0)和(15,0)是兩個比較特殊的情況。(0,0)表示塊結束標誌(EOB),(15,0)表示ZRL,當行程長度超過15時,用增加ZRL的個數來解決,所以最多有三個ZRL(3×16+15=63)。符號2爲幅度值(Amplitude)。
對於DC係數,也有兩個符號。符號1爲尺寸(Size);符號2爲幅度值(Amplitude)。
(2)熵編碼
對於AC係數,符號1和符號2分別進行編碼。零行程長度超過15個時,有一個符號(15,0),塊結束時只有一個符號(0,0)。
對符號1進行Hufffman編碼(亮度,色差的Huffman碼錶不同)。對符號2進行變長整數VLI編碼。舉例來說:Size=6時,Amplitude的範圍是-63~-32,以及32~63,對絕對值相同,符號相反的碼字之間爲反碼關係。所以AC係數爲32的碼字爲100000,33的碼字爲100001,-32的碼字爲011111,-33的碼字爲011110。符號2的碼字緊接於符號1的碼字之後。
對於DC係數,Y和UV的Huffman碼錶也不同。
掉了這麼半天的書包,你可能已經暈了,呵呵。舉個例子來說明上述過程就容易明白了。
下面爲8×8的亮度(Y)圖象子塊經過量化後的係數。
15 0 -1 0 0 0 0 0
-2 -1 0 0 0 0 0 0
-1 -1 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
可見量化後只有左上角的幾個點(低頻分量)不爲零,這樣採用行程編碼就很有效。
第一步,熵編碼的中間格式表示:先看DC係數。假設前一個8×8子塊DC係數的量化值爲12,則本塊DC係數與它的差爲3,根據下表
Size Amplitude
0 0
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
11 –2047~-1024,1024~2047
查表得Size=2,Amplitude=3,所以DC中間格式爲(2)(3)。
下面對AC係數編碼。經過Zig-Zag掃描後,遇到的第一個非零係數爲-2,其中遇到零的個數爲1(即RunLength),根據下面這張AC係數表:
Size Amplitude
1 –1,1
2 –3,-2,2,3
3 –7~-4,4~7
4 –15~-8,8~15
5 –31~-16,16~31
6 –63~-32,32~63
7 –127~-64,64~127
8 –255~-128,128~255
9 –511~-256,256~511
10 –1023~512,512~1023
查表得Size=2。所以RunLength=1,Size=2,Amplitude=3,所以AC中間格式爲(1,2)(-2)。
其餘的點類似,可以求得這個8×8子塊熵編碼的中間格式爲
(DC)(2)(3),(1,2)(-2),(0,1)(-1),(0,1)(-1),(0,1)(-1),(2,1)(-1),(EOB)(0,0)
第二步,熵編碼:
對於(2)(3):2查DC亮度Huffman表得到11,3經過VLI編碼爲011;
對於(1,2)(-2):(1,2)查AC亮度Huffman表得到11011,-2是2的反碼,爲01;
對於(0,1)(-1):(0,1)查AC亮度Huffman表得到00,-1是1的反碼,爲0;
……
最後,這一8×8子塊亮度信息壓縮後的數據流爲11011, 1101101, 000, 000, 000, 111000,1010。總共31比特,其壓縮比是64×8/31=16.5,大約每個象素用半個比特。