作者簡介 孫龍波,攜程內(nèi)容信息研發(fā)部 Native 開發(fā) leader。目前主要負(fù)責(zé)攜程攻略,行程,視頻直播等項目的前端開發(fā)和團(tuán)隊管理。 隨著抖音,快手等APP的迅猛發(fā)展,短視頻在移動端的地位越來越突出。而視頻壓縮是視頻傳輸中很關(guān)鍵的一步。 本文會通過一個示例引入視頻的一些基本概念并做稍微深入的介紹,最終給出在iOS上實現(xiàn)自定義碼率和分辨率的視頻壓縮方案。這篇文章同時也是一個大雜燴,對于很多首次接觸視頻領(lǐng)域的同學(xué)是一個不錯的入門文章。 產(chǎn)品需求:不管原視頻的清晰度如何,壓縮后的視頻碼率和分辨率是一樣的。大家首先想到的應(yīng)該是iOS在AVFoundation中已經(jīng)提供了簡單的視頻壓縮方法,示例代碼如下: 正常情況下這段代碼不會出現(xiàn)任何問題,但是大家可以用下面的視頻做個測試,鏈接: https://pan.baidu.com/s/1wLVbDFtzROVPo8T1qw6MXA 密碼: ij7d。 結(jié)果會發(fā)現(xiàn)原視頻分辨率1080x608,大小 90M,經(jīng)過上面的代碼壓縮后變成了分辨率960x540, 大小147M!分辨率降低但是文件大小增加了! 輸出的日志如下: 問題出在哪里?這個視頻有什么特殊的地方?我們嘗試用mediainfo工具查看壓縮前后兩個視頻的詳細(xì)參數(shù)。
原視頻參數(shù)信息 壓縮后的視頻參數(shù):
首先我們要清楚截圖中幾個關(guān)鍵指標(biāo)的含義。 1)碼率(bit rate)是指數(shù)據(jù)傳輸時單位時間傳送的數(shù)據(jù)位數(shù),單位是bit per second(bps)。簡單的說碼率=視頻文件大小/視頻時長。 2)幀率(frame rate)指每秒鐘有多少個畫面,單位Frame Per Second簡稱FPS。視頻實際是由一組連續(xù)的圖片組成的,由于人眼有視覺暫留現(xiàn)象,畫面幀率高于16的時候大腦就會把圖片連貫成動畫,高于24大腦就認(rèn)為是非常流暢了。所以24FPS是視頻行業(yè)的標(biāo)準(zhǔn)。 但這并不是人眼的極限,幀率繼續(xù)提高能獲取更好更流暢的體驗,直到人眼無法區(qū)別(極限因人而異,美國空軍曾做過一項測試,極限大概是220FPS,正常人遠(yuǎn)低于這個數(shù)字)。所以游戲行業(yè)為了更逼真的效果獲取更好的用戶體驗將標(biāo)準(zhǔn)定為30FPS 3)分辨率:習(xí)慣上我們說的分辨率是指圖像的高/寬像素值,嚴(yán)格意義上的分辨率是指單位長度內(nèi)的有效像素值ppi(每英寸像素Pixel per inch)。差別是,圖像的高/寬像素值和尺寸無關(guān),但單位長度內(nèi)的有效像素值ppi和尺寸就有關(guān)了。比如,同樣Width x Height的圖片,尺寸越大ppi越小。 解釋完上面幾個概念大家可以得出比較直觀的結(jié)論,幀率相同的情況下(壓縮前后都是30FPS),分辨率越高碼率越大,但是截圖的中的參數(shù)顯示碼率大的分辨率低。仔細(xì)對比兩個視頻的參數(shù)會發(fā)現(xiàn)唯一有區(qū)別的是 Format profile,這個參數(shù)才是問題的根源。 在介紹這個參數(shù)之前需要了解另一個概念,H264視頻編碼。所謂視頻編碼方式就是指通過特定的壓縮技術(shù),將某個視頻格式的文件轉(zhuǎn)換成另一種視頻格式文件的方式。 如果視頻不編碼會出現(xiàn)什么后果?我們來計算一下,以原視頻為例,每秒鐘包含了30張1080x600的圖片,那一秒鐘的視頻大小應(yīng)該是 1080x600*30/(1024*1024*8) = 2.3 MB. 這個視頻有3分42秒 ,文件大小應(yīng)該是 2.3*222 = 510MB 遠(yuǎn)超過95M。既然編碼是必須的那編碼標(biāo)準(zhǔn)有哪些呢? 國際上制定視頻編解碼技術(shù)的組織有兩個,一個是“國際電聯(lián)(ITU-T)”,它制定的標(biāo)準(zhǔn)有H.261、H.263、H.263 等,另一個是“國際標(biāo)準(zhǔn)化組織(ISO)”它制定的標(biāo)準(zhǔn)有MPEG-1、MPEG-2、MPEG-4等。 而H.264則是由兩個組織聯(lián)合組建的聯(lián)合視頻組(JVT)共同制定的新數(shù)字視頻編碼標(biāo)準(zhǔn),所以它既是ITU-T的H.264,又是ISO/IEC的MPEG-4高級視頻編碼(Advanced Video Coding,AVC)的第10 部分。所以大家在用不同工具查看同一個視頻時有時候會顯示AVC有時候會顯示H.264實際是同一種編碼方式。
而H264最大的優(yōu)勢就是低碼率情況下提供高質(zhì)量的視頻圖像。怎么做到的?這個問題比較復(fù)雜可以新開一篇文章來專門介紹了。有興趣的大家可以看一下這篇介紹:http://read./downloads147/ebook/635957/%E6%96%B0%E4%B8%80%E4%BB%A3%E8%A7%86%E9%A2%91%E5%8E%8B%E7%BC%A9%E7%BC%96%E7%A0%81%E6%A0%87%E5%87%86H.264.pdf
總的來說編碼流程可以分為五部分:幀間和幀內(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可以細(xì)分為十幾種,實際使用的主要有以下四種, 1)BaslineProfile:支持I/P 幀,只支持無交錯(Progressive)和CAVLC Extended Profile:支持I/P/B/SP/SI 幀,只支持無交錯(Progressive)和CAVLC 2)MainProfile:提供I/P/B 幀,支持無交錯(Progressive)和交錯(Interlaced),也支持CAVLC 和CABAC 3)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è)備性能也就越高,編碼、解碼的效率也就越低。
回到之前的兩個視頻信息,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的能力細(xì)分。 而3.1規(guī)定的最高標(biāo)準(zhǔn)如下:
了解完視頻的profile和level之后,大家會有疑問,既然每種profile對設(shè)備性能的要求不同,蘋果的不同機型對各種profile支持程度是怎樣的?可以參照下面的列表:
基本概念都搞清楚了,而我們只需要支持iphone 5C以上機型的背景下,要想獲得最大的視頻壓縮率采取的最好辦法就是: (1)指定highprofile (2)降低幀率 (3)適當(dāng)降低分辨率 最終來獲取更低的碼率。 問題來了,文章最開始的壓縮方式不支持指定profile,幀率和碼率。所以只有通過其他方式來實現(xiàn)。參照了括蘋果官網(wǎng)的一個錄像時自定義碼率的實現(xiàn) https://developer.apple.com/library/archive/samplecode/RosyWriter/Introduction/Intro.html 在錄像時需要將拍攝的每一幀sampleBuffer(音頻或者視頻)傳給assetWriter,并制定壓縮參數(shù)。 而我們要實現(xiàn)的是視頻壓縮,不是錄像,怎么辦?思路很簡單,先通過assetReader取出每一幀sampleBuffer(音頻或視頻),然后指定壓縮參數(shù)后將每一幀傳給assetWriter最終實現(xiàn)自定義壓縮的目的。具體的流程如下: 1)初始化 reader,writer,video/audio track, video/audio input, video/audio output 2)指定音視頻的壓縮碼率,profile,幀率等關(guān)鍵參數(shù)信息
3)開始讀寫 4)視頻逐幀寫入 5)音頻逐幀寫入
6)完成壓縮
壓縮效果如下: 最終自定義的視頻壓縮方案有了,其實逐幀寫入還可以做添加水印,濾鏡等動作,之后可以在后續(xù)的文章里進(jìn)一步介紹。 |
|