編輯:關於Android編程
最近在做一個直播的android手機app,難點在於流媒體的處理,主要是對流媒體進行編碼與傳輸,在此用H264編碼,傳輸協議采用RTMP,流媒體服務器用nginx並進行配置。本文先寫編碼相關的知識。
所謂視頻編碼方式就是指通過特定的壓縮技術,將某個視頻格式的文件轉換成另一種視頻格式文件的方式。
壓縮技術:
有損壓縮:將視頻數字信號合並整理,信號本身沒有損失
無損壓縮:進一步根據人眼的特性(諸如時滯性等),減少信號兩,信號本身有一定的損失,也就是圖象質量有損失。
編碼方案
音頻視頻編碼方法有很多,主要有2類:
MPEG系列:
(由ISO[國際標准組織機構]下屬的MPEG[運動圖象專家組]開發 )視頻編碼方面主要是Mpeg1(vcd用的就是它)、Mpeg2(DVD使用)、Mpeg4(的DVDRIP使用的都是它的變種,如:divx,xvid等)、Mpeg4 AVC(正熱門);音頻編碼方面主要是MPEG Audio Layer 1/2、MPEG Audio Layer 3(大名鼎鼎的mp3)、MPEG-2 AAC 、MPEG-4 AAC等等。注意:DVD音頻沒有采用Mpeg的。
H.26X系列:
(由ITU[國際電傳視訊聯盟]主導,側重網絡傳輸,注意:只是視頻編碼)
包括H.261、H.262、H.263、H.263+、H.263++、H.264(就是MPEG4 AVC-合作的結晶)[1]
編碼原理
數字化後的視頻信號能進行壓縮主要依據兩個基本條件:
數據冗余:
例如如空間冗余、時間冗余、結構冗余、信息熵冗余等,即圖像的各像素之間存在著很強的相關性。消除這些冗余並不會導致信息損失,屬於無損壓縮。
視覺冗余:
人眼的一些特性比如亮度辨別阈值,視覺阈值,對亮度和色度的敏感度不同,使得在編碼的時候引入適量的誤差,也不會被察覺出來。可以利用人眼的視覺特性,以一定的客觀失真換取數據壓縮。這種壓縮屬於有損壓縮。
數字視頻信號的壓縮正是基於上述兩種條件,使得視頻數據量得以極大的壓縮,有利於傳輸和存儲。一般的數字視頻壓縮編碼方法都是混合編碼,即將變換編碼,運動估計和運動補償,以及熵編碼三種方式相結合來進行壓縮編碼。通常使用變換編碼來消去除圖像的幀內冗余,用運動估計和運動補償來去除圖像的幀間冗余,用熵編碼來進一步提高壓縮的效率。
視頻圖像數據有極強的相關性,也就是說有大量的冗余信息。其中冗余信息可分為空域冗余信息和時域冗余信息。壓縮技術就是將數據中的冗余信息去掉(去除數據之間的相關性),壓縮技術包含幀內圖像數據壓縮技術、幀間圖像數據壓縮技術和熵編碼壓縮技術。
去時域
使用幀間編碼技術可去除時域冗余信息,它包括以下三部分:
- 運動補償
運動補償是通過先前的局部圖像來預測、補償當前的局部圖像,它是減少幀序列冗余信息的有效方法。
- 運動表示
不同區域的圖像需要使用不同的運動矢量來描述運動信息。運動矢量通過熵編碼進行壓縮。
-運動估計
運動估計是從視頻序列中抽取運動信息的一整套技術。
注:通用的壓縮標准都使用基於塊的運動估計和運動補償。 去空域
主要使用幀內編碼技術和熵編碼技術:
-變換編碼
幀內圖像和預測差分信號都有很高的空域冗余信息。變換編碼將空域信號變換到另一正交矢量空間,使其相關性下降,數據冗余度減小。
- 量化編碼
經過變換編碼後,產生一批變換系數,對這些系數進行量化,使編碼器的輸出達到一定的位率。這一過程導致精度的降低。
-熵編碼
熵編碼是無損編碼。它對變換、量化後得到的系數和運動信息,進行進一步的壓縮。
H264編碼原理
H264是新一代的編碼標准,以高壓縮高質量和支持多種網絡的流媒體傳輸著稱,在編碼方面,我理解的他的理論依據是:參照一段時間內圖像的統計結果表明,在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內。所以對於一段變化不大圖像畫面,我們可以先編碼出一個完整的圖像幀A,隨後的B幀就不編碼全部圖像,只寫入與A幀的差別,這樣B幀的大小就只有完整幀的1/10或更小!B幀之後的C幀如果變化不大,我們可以繼續以參考B的方式編碼C幀,這樣循環下去。這段圖像我們稱為一個序列(序列就是有相同特點的一段數據),當某個圖像與之前的圖像變化很大,無法參考前面的幀來生成,那我們就結束上一個序列,開始下一段序列,也就是對這個圖像生成一個完整幀A1,隨後的圖像就參考A1生成,只寫入與A1的差別內容。
在H264協議裡定義了三種幀,完整編碼的幀叫I幀,參考之前的I幀生成的只包含差異部分編碼的幀叫P幀,還有一種參考前後的幀編碼的幀叫B幀。
H264采用的核心算法是幀內壓縮和幀間壓縮,幀內壓縮是生成I幀的算法,幀間壓縮是生成B幀和P幀的算法。
序列的說明
在H264中圖像以序列為單位進行組織,一個序列是一段圖像編碼後的數據流,以I幀開始,到下一個I幀結束。
一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這裡可以獲得重新同步的機會。IDR圖像之後的圖像永遠不會使用IDR之前的圖像的數據來解碼。
一個序列就是一段內容差異不太大的圖像編碼後生成的一串數據流。當運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內容變動很小,所以就可以編一個I幀,然後一直P幀、B幀了。當運動變化多時,可能一個序列就比較短了,比如就包含一個I幀和3、4個P幀。
三種幀的說明
1、I幀
I幀:幀內編碼幀 ,I幀表示關鍵幀,你可以理解為這一幀畫面的完整保留;解碼時只需要本幀數據就可以完成(因為包含完整畫面)
I幀特點:
1)它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸;
2)解碼時僅用I幀的數據就可重構完整圖像;
3)I幀描述了圖像背景和運動主體的詳情;
4)I幀不需要參考其他畫面而生成;
5)I幀是P幀和B幀的參考幀(其質量直接影響到同組中以後各幀的質量);
6)I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀;
7)I幀不需要考慮運動矢量;
8)I幀所占數據的信息量比較大。 2、P幀
P幀:前向預測編碼幀。P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)
P幀的預測與重構:P幀是以I幀為參考幀,在I幀中找出P幀“某點”的預測值和運動矢量,取預測差值和運動矢量一起傳送。在接收端根據運動矢量從I幀中找出P幀“某點”的預測值並與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。
P幀特點:
1)P幀是I幀後面相隔1~2幀的編碼幀;
2)P幀采用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差);
3)解碼時必須將I幀中的預測值與預測誤差求和後才能重構完整的P幀圖像;
4)P幀屬於前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀;
5)P幀可以是其後面P幀的參考幀,也可以是其前後的B幀的參考幀;
6)由於P幀是參考幀,它可能造成解碼錯誤的擴散;
7)由於是差值傳送,P幀的壓縮比較高。 3、B幀
B幀:雙向預測內插編碼幀。B幀是雙向差別幀,也就是B幀記錄的是本幀與前後幀的差別(具體比較復雜,有4種情況,但我這樣說簡單些),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之後的畫面,通過前後畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累。
B幀的預測與重構
B幀以前面的I或P幀和後面的P幀為參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,並取預測差值和運動矢量傳送。接收端根據運動矢量在兩個參考幀中“找出(算出)”預測值並與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀。
B幀特點
1)B幀是由前面的I或P幀和後面的P幀來進行預測的;
2)B幀傳送的是它與前面的I或P幀和後面的P幀之間的預測誤差及運動矢量;
3)B幀是雙向預測編碼幀;
4)B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預測比較准確;
5)B幀不是參考幀,不會造成解碼錯誤的擴散。
注:I、B、P各幀是根據壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I幀的壓縮率是7(跟JPG差不多),P幀是20,B幀可以達到50。可見使用B幀能節省大量空間,節省出來的空間可以用來保存多一些I幀,這樣在相同碼率下,可以提供更好的畫質。
壓縮算法的說明
h264的壓縮方法:
1.分組:把幾幀圖像分為一組(GOP,也就是一個序列),為防止運動變化,幀數不宜取多。
2.定義幀:將每組內各幀圖像定義為三種類型,即I幀、B幀和P幀;
3.預測幀:以I幀做為基礎幀,以I幀預測P幀,再由I幀和P幀預測B幀;
4.數據傳輸:最後將I幀數據與預測的差值信息進行存儲和傳輸。
幀內(Intraframe)壓縮也稱為空間壓縮(Spatial compression)。當壓縮一幀圖像時,僅考慮本幀的數據而不考慮相鄰幀之間的冗余信息,這實際上與靜態圖像壓縮類似。幀內一般采用有損壓縮算法,由於幀內壓縮是編碼一個完整的圖像,所以可以獨立的解碼、顯示。幀內壓縮一般達不到很高的壓縮,跟編碼jpeg差不多。
幀間(Interframe)壓縮的原理是:相鄰幾幀的數據有很大的相關性,或者說前後兩幀信息變化很小的特點。也即連續的視頻其相鄰幀之間具有冗余信息,根據這一特性,壓縮相鄰幀之間的冗余量就可以進一步提高壓縮量,減小壓縮比。幀間壓縮也稱為時間壓縮(Temporal compression),它通過比較時間軸上不同幀之間的數據進行壓縮。幀間壓縮一般是無損的。幀差值(Frame differencing)算法是一種典型的時間壓縮法,它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數據量。
NAL簡介與I幀判斷
1、NAL全稱Network Abstract Layer, 即網絡抽象層。
在H.264/AVC視頻編碼標准中,整個系統框架被分為了兩個層面:視頻編碼層面(VCL)和網絡抽象層面(NAL)。其中,前者負責有效表示視頻數據的內容,而後者則負責格式化數據並提供頭信息,以保證數據適合各種信道和存儲介質上的傳輸。因此我們平時的每幀數據就是一個NAL單元(SPS與PPS除外)。在實際的H264數據幀中,往往幀前面帶有00 00 00 01 或 00 00 01分隔符,一般來說編碼器編出的首幀數據為PPS與SPS,接著為I幀……
如下圖:
2、如何判斷幀類型(是圖像參考幀還是I、P幀等)?
NALU類型是我們判斷幀類型的利器,從官方文檔中得出如下圖:
我們還是接著看最上面圖的碼流對應的數據來層層分析,以00 00 00 01分割之後的下一個字節就是NALU類型,將其轉為二進制數據後,解讀順序為從左往右算,如下:
(1)第1位禁止位,值為1表示語法出錯
(2)第2~3位為參考級別
(3)第4~8為是nal單元類型
例如上面00000001後有67,68以及65
其中0x67的二進制碼為:
0110 0111
4-8為00111,轉為十進制7,參考第二幅圖:7對應序列參數集SPS
其中0x68的二進制碼為:
0110 1000
4-8為01000,轉為十進制8,參考第二幅圖:8對應圖像參數集PPS
其中0x65的二進制碼為:
0110 0101
4-8為00101,轉為十進制5,參考第二幅圖:5對應IDR圖像中的片(I幀)
所以判斷是否為I幀的算法為: (NALU類型 & 0001 1111) = 5 即 NALU類型 & 31 = 5
比如0x65 & 31 = 5
一些名詞解釋:
VCL video coding layer 視頻編碼層
NAL network abstraction layer 網絡提取層
PTS:Presentation Time Stamp。PTS主要用於度量解碼後的視頻幀什麼時候被顯示出來
DTS:Decode Time Stamp。DTS主要是標識讀入內存中的bit流在什麼時候開始送入解碼器中進行解碼。
序列的參數集(SPS):包括了一個圖像序列的所有信息,
圖像的參數集(PPS):包括了一個圖像所有片的信息。
NAL以NALU(NAL unit)為單元來支持編碼數據在基於分組交換技術網絡中傳輸。 它定義了符合傳輸層或存儲介質要求的數據格式,同時給出頭信息,從而提供了視頻編碼和外部世界的接口。
NALU:定義了可用於基於分組和基於比特流系統的基本格式 RTP封裝:只針對基於NAL單元的本地NAL接口。
三種不同的數據形式:
SODB 數據比特串-->最原始的編碼數據
RBSP 原始字節序列載荷-->在SODB的後面填加了結尾比特(RBSP trailing bits 一個bit“1”)若干比特“0”,以便字節對齊
EBSP 擴展字節序列載荷–>在RBSP基礎上填加了仿校驗字節(0X03)它的原因是: 在NALU加到Annexb上時,需要添加每 組NALU之前的開始碼
1.Animation 動畫類型Android的animation由四種類型組成:XML中 alph 漸變透明度動畫效果 scale 漸變尺寸伸縮動畫效果 tr
Android自帶的對話框標題不好看,如果我們需要給彈出的對話框設置一個自己定義的標題,可以使用AlertDialog.Builder的setCustomTitle()方
相關地址介紹 :--Universal Image Loader 項目 GitHub 官方地址https://github.com/nostra13/Android-Un
Android手機同時使用Wi-Fi和數據流量大家都知道,當手機成功連接到Wi-Fi熱點以後,手機所產生的上網流量都是通過Wi-Fi來傳輸的,而手機的移動流量會被禁用。但