最近在開發(fā)過程中涉及到了視頻壓縮的需求,那么在 iOS 上怎么實現(xiàn)自定義碼率和分辨率的視頻壓縮呢?
1. 傳統(tǒng)壓縮方式
產(chǎn)品需求:不管原視頻的清晰度如何,壓縮后的視頻碼率和分辨率是一樣的。首先,iOS在AVFoundation中已經(jīng)提供了簡單的視頻壓縮方法,示例代碼如下:
正常情況下這段代碼不會出現(xiàn)任何問題,但是大家可以用下面的視頻做個測試,鏈接: https://pan.baidu.com/s/1wLVbDFtzROVPo8T1qw6MXA 密碼: ij7d。結(jié)果會發(fā)現(xiàn)原視頻分辨率1080x608,大小 90M,經(jīng)過上面的代碼壓縮后變成了分辨率960x540, 大小147M!雖然分辨率降低,但文件大小增加了!
2. 壓縮參數(shù)分析
可以使用 mediainfo 工具查看壓縮前后兩個視頻的詳細參數(shù)信息。
原視頻參數(shù):
壓縮視頻參數(shù):
碼率:bit rate,是指單位時間內(nèi)處理的數(shù)據(jù)位數(shù),單位是 b/s 。碼率=視頻文件大小/視頻時長。
幀率:frame rate,是指每秒鐘有多少個畫面,單位 f/s 。視頻畫面幀率高于16 時大腦就會把圖片連貫成動畫,高于24大腦就認為是非常流暢了。因此,24FPS是視頻行業(yè)的標(biāo)準。
分辨率:通常我們了解的分辨率是指圖像的高/寬像素值,嚴格意義上的分辨率是指單位長度內(nèi)的有效像素值ppi(每英寸像素Pixel per inch)。差別是,圖像的高/寬像素值和尺寸無關(guān),但單位長度內(nèi)的有效像素值ppi和尺寸就有關(guān)了。比如,同樣Width x Height的圖片,尺寸越大ppi越小。
3. 視頻編碼標(biāo)準
根據(jù)上面的概念得出,幀率相同的情況下(壓縮前后都是30FPS),分辨率越高碼率越大,但是截圖的中的參數(shù)顯示碼率大的分辨率低。仔細對比兩個視頻的參數(shù)會發(fā)現(xiàn)唯一有區(qū)別的是 Format profile,這個參數(shù)才是問題的根源。
在介紹這個參數(shù)之前需要了解另一個概念,H264視頻編碼。所謂視頻編碼方式就是指通過特定的壓縮技術(shù),將某個視頻格式的文件轉(zhuǎn)換成另一種視頻格式文件的方式。
如果視頻不編碼會出現(xiàn)什么后果?我們來計算一下,以原視頻為例,每秒鐘包含了30張1080x600的圖片,那一秒鐘的視頻大小應(yīng)該是 1080x60030/(102410248) = 2.3 MB. 這個視頻有3分42秒 ,文件大小應(yīng)該是 2.3222 = 510MB 遠超過95M。既然編碼是必須的那編碼標(biāo)準有哪些呢?
國際上制定視頻編解碼技術(shù)的組織有兩個,一個是“國際電聯(lián)(ITU-T)”,它制定的標(biāo)準有H.261、H.263、H.263+等,另一個是“國際標(biāo)準化組織(ISO)”它制定的標(biāo)準有MPEG-1、MPEG-2、MPEG-4等。
而H.264則是由兩個組織聯(lián)合組建的聯(lián)合視頻組(JVT)共同制定的新數(shù)字視頻編碼標(biāo)準,所以它既是ITU-T的H.264,又是ISO/IEC的MPEG-4高級視頻編碼(Advanced Video Coding,AVC)的第10 部分。所以大家在用不同工具查看同一個視頻時有時候會顯示AVC有時候會顯示H.264實際是同一種編碼方式。
4. H264 編碼詳解
而H264最大的優(yōu)勢就是低碼率情況下提供高質(zhì)量的視頻圖像,有興趣的同學(xué)新一代視頻壓縮編碼標(biāo)準 — H.264/AVC。
總的來說編碼流程可以分為五部分:幀間和幀內(nèi)預(yù)測(Estimation)、變換(Transform)和反變換、量化(Quantization)和反量化、環(huán)路濾波(Loop Filter)、熵編碼(Entropy Coding)。而H264為了滿足不同設(shè)備不同場景的需要(比如直播注重實時性,存儲注重壓縮比)定義了多種編碼層次也就是Profile,官方給Profile的定義是:
The standarddefines a set of capabilities, which are referred to as profiles,targeting specific classes of applications. These are declared as a profilecode (profile_idc) and a set of constraints applied in the encoder. This allowsa decoder to recognize the requirements to decode that specific stream.
Profiles可以細分為十幾種,實際使用的主要有以下四種,
1)BaslineProfile:支持I/P 幀,只支持無交錯(Progressive)和CAVLC
2)Extended Profile:支持I/P/B/SP/SI 幀,只支持無交錯(Progressive)和CAVLC
3)MainProfile:提供I/P/B 幀,支持無交錯(Progressive)和交錯(Interlaced),也支持CAVLC 和CABAC
4)High Profile:在mainProfile 的基礎(chǔ)上增加了8x8內(nèi)部預(yù)測、自定義量化、 無損視頻編碼和更多的YUV 格式;
大家對里面的術(shù)語可能不太理解,簡單介紹下。
視頻壓縮很重要的一個就是幀間預(yù)測,也就是視頻相鄰的幾幀有很大的相關(guān)性,變化不會太大,所以存在很多冗余信息,壓縮要做的就是去除這些冗余信息。幀類型主要有以下幾種
1)I幀表示關(guān)鍵幀,這一幀保留完整的畫面數(shù)據(jù),解碼時只需要本幀數(shù)據(jù)就可以完成
2)P幀,前向預(yù)測幀,表示的是這一幀跟之前的一個關(guān)鍵幀(或P幀)的差別,解碼時需要用之前的畫面疊加上本幀定義的差別,生成最終畫面。
3)B幀是雙向預(yù)測幀,也就是B幀記錄的是本幀與前后幀的差別,要解碼B幀,不僅要取得之前的畫面,還要解碼之后的畫面,通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B幀壓縮率高,但是解碼時比較耗費CPU 。
總結(jié)起來就是Profile 越高,壓縮比就越高,但是編碼、解碼時要求的設(shè)備性能也就越高,編碼、解碼的效率也就越低。
5. Profile 與 Level 詳解
回到之前的兩個視頻信息,profile分別是main@L3.1,high@L3.1, 現(xiàn)在我們搞清楚了main和high是profile,L3.1是什么?這個是profile的碼流級別,同樣給出官方的定義:
As the term is used in the standard, a "level" is aspecified set of constraints that indicate a degree of required decoderperformance for a profile. For example, a level of support within a profilespecifies the maximum picture resolution, frame rate, and bit rate that adecoder may use. A decoder that conforms to a given level must be able todecode all bitstreams encoded for that level and all lower levels.
簡單的說level就是對每個profile的能力細分。
而3.1規(guī)定的最高標(biāo)準如下:

6. iOS 設(shè)備對 Profile 和 level 的支持情況
了解完視頻的profile和level之后,大家會有疑問,既然每種profile對設(shè)備性能的要求不同,蘋果的不同機型對各種profile支持程度是怎樣的?可以參照下面的列表:
iPhone 3GS 和更早的設(shè)備支持 Baseline Profile level 3.0 及更低的級別;
iPhone 4S 支持 High Profile level 4.1 及更低的級別;
iPhone 5C 支持 High Profile level 4.1 及更低的級別;
iPhone 5S 支持 High Profile level 4.1 及更低的級別;
iPad 1 支持 Main Profile level 3.1 及更低的級別;
iPad 2 支持 Main Profile level 3.1 及更低的級別;
iPad with Retina display 支持 High Profile level 4.1 及更低的級別;
iPad mini 支持 High Profile level 4.1 及更低的級別。
7. 自定義視頻壓縮方案
獲得最大的視頻壓縮率采取的最好辦法就是:
- 指定highprofile
- 降低幀率
- 適當(dāng)降低分辨率
最終來獲取更低的碼率。 問題來了,文章最開始的壓縮方式不支持指定profile,幀率和碼率,所以只有通過其他方式來實現(xiàn)。在相機錄像時需要將拍攝的每一幀sampleBuffer(音頻或者視頻)傳給assetWriter,并制定壓縮參數(shù)。
而視頻壓縮不是錄像,怎么辦?思路很簡單,先通過assetReader取出每一幀sampleBuffer(音頻或視頻),然后指定壓縮參數(shù)后將每一幀傳給assetWriter最終實現(xiàn)自定義壓縮的目的。具體的流程如下:
代碼實現(xiàn)
1)初始化 reader,writer,video/audio track, video/audio input, video/audio output
2)指定音視頻的壓縮碼率,profile,幀率等關(guān)鍵參數(shù)信息
3)開始讀寫
4)視頻逐幀寫入
5)音頻逐幀寫入
6)完成壓縮
壓縮效果如下:
最終自定義的視頻壓縮方案有了,其實逐幀寫入還可以做添加水印,濾鏡等動作。
感謝!