說到安卓的視訊開發,大多數朋友們都是用著開源的播放器,或者安卓自帶的native mediaplayer,拿來主義居多,我曾經也是。。。 最近這半年因為開始著手重構公司的播放器,也開始學習了很多視訊音訊開發的相關知識,抱著獨樂樂不如眾樂樂的想法,開始寫一些值得分享的東西。這次的連載和之前的RxJava分享一樣,會分開不容的章節。
第一次我打算分享一下視訊開發中常見的一些知識點,概念和術語,給不熟悉的朋友們先"掃掃盲"。在之後的章節我會慢慢的介紹除了基本的線上視訊播放技術之外,一些更加“高階”的技術 :smirk:,包括安卓平臺在4.4之後釋出的全新的Codec API, 還有怎麼處理自適應視訊播放(Adaptive Streaming),版權管理內容(DRM Content),最後幾章會使用谷歌開源的ExoPlayer作為例子,從原始碼的角度分析一個完整的播放器需要哪些構件。
每一個術語我都會盡量用中文寫一遍,再寫一遍英文,因為說實話。。。不用英文查資料,很多東西都搜不出來。
- 什麼是Codec
- 什麼是Container format file
- 視訊處理的流程-從後臺到前端
(華麗麗的分割線)
1.什麼是Codec
一說到視訊,音訊,大家肯定都聽說,至少有所耳聞這兩個詞 - 編碼(encode) 和 解碼(decode)。 我這裡提到的Codec就是一種程式,這種程式可以對視訊檔案進行編碼和解碼。在維基百科上對Codec是這樣定義的:
A video codec is an electronic circuit or software that compresses or decompresses digital video. It converts raw (uncompressed) digital video to a compressed format or vice versa. In the context of video compression, "codec" is a concatenation of "encoder" and "decoder"—a device that only compresses is typically called an encoder, and one that only decompresses is a decoder.
那麼問題來了,視訊不就是視訊嗎,MP4,avi,rmvb,我們看的很多小電影不就是視訊嘛。。。下載下來就可以看了啊。。。。為何需要編碼解碼。。。都是什麼鬼。
...
首先,我們常說編碼 就是壓縮,解碼 就是解壓縮。視訊檔案的本質其實就是圖片的集合而已,當一段連續的圖片不斷的出現在人眼前(一般一個連貫的電影或者動畫至少要求一秒24幀,也就是一秒內連續出現24張圖片),肉眼就會“欺騙性”的告訴大腦我們在看一個視訊,而不是幻燈片。
那我們可以開始做點算術題了,假設一張畫素為1280X720(清晰度,寬1280個畫素點,高720個畫素點)的圖片,大小為約為1280X720X3 bytes,就是2.7MB。大家可以猜想一下為何我這裡還需要乘以一個數字3.那麼一段60秒鐘的小電影,就需要60X24(24張圖片)X2.7MB ,約為3.9GB了!
之所以圖片大小是畫素寬高相乘還要乘3 是因為一個畫素點需要至少三原色(RGB)來顯示畫素點本身的顏色,做過安卓開發的同學都知道在xml裡面定義顏色的格式吧?#ffffff - 代表白色 f是十六進位制數,也就是4位二進位制數,三原色需要3X4X2位二進位制數,也就是3個八位,一個八位是一個位元組,所以我們需要3個位元組來顯示一個畫素點
這tm必然是不能接受的啊!這樣我用我3TB的行動硬碟,也不能把蒼老師的全部小電影儲存起來,寶寶心裡苦啊!
所以Codec這種程式就出現了,它會把這些連續的圖片們通過一定的演算法壓縮成體積更小的檔案格式,這就是我們所謂的編碼,壓縮。但是在播放器的客戶端,不管是PC,手機也好,他們要顯示在螢幕上的,必須是實實在在的圖片啊,所以這些被壓縮過的檔案最終又必須被還原成圖片格式,這就是解碼,解壓縮。
視訊編碼,壓縮是一個非常複雜的過程,萬幸的是,現在市面上已經有很多工具,還有現有規範來指導開發者進行編碼解碼了。其中最常用的一些規範是:
可能大家對壓縮解壓縮還是不太理解。。。到底有哪些地方可以壓縮呢? 那我們舉個例子!
我們們想象一下一個場景,比如說在某些電影中,主人公在安靜的公園中因為失戀悲傷不已,全世界都彷彿靜止一般。。。。就這麼呆坐了整整30s。那麼對於這種“靜態的場景”,視訊壓縮演算法會只取這三十秒的前幾幀作為基準幀圖片,對其餘的29s的幀,採取只儲存“不同的部分”的策略,這樣就不用儲存這些差不多相同的圖片,這種做法叫“去冗餘”。大大減少了視訊的體積。
當然,這只是視訊壓縮演算法的冰山一角,我們不多研究。
另外需要注意的是,Codec的編碼與解碼包含對視訊資料的編碼解碼和音訊資料的編碼解碼,因為音訊的本質是聲波資訊,視訊是圖片處理,他們本質上是不同的,我這裡主要是介紹視訊資料的處理。
回到我們說的Codec,所以說Codec是一套程式,它遵循不同的規範,根據規範的不同提供不同的壓縮解壓縮策略。 既然是一套規範,那麼就肯定需要實現啊! 在安卓平臺裡面,谷歌提供了視訊編碼解碼的API,對一些基礎的編碼解碼規範做了API的封裝,在接下里的章節我會慢慢介紹,其他移動平臺也都差不多,多多少少都會提供API的支援。
2. 什麼是Container format file(視訊容器檔案)
之前說到,我們們在看小電影的時候都會看到很多檔案的字尾名,例如mp4,rmvb,avi,喜歡看高清美劇的同學應該還會經常看到所謂的藍光mkv格式等等。我們習慣叫他們視訊檔案,但是這樣說顯得不夠專業。。。
嚴格的來講,他們應該被叫做容器檔案。。。。因為一個容器裡,不僅僅包括了視訊(video)資料,還包括了(audio)音訊資料,有的容器還內嵌字幕,那麼就還有文字(Text)資料。不過容器檔案雖然聽起來嚇人,但是它說到底也就是一個結構化的檔案而已。之所以說它結構化,就是它包含的視訊,音訊,文字資料都必須按照一定的規範,放在檔案指定的位置(方便播放器解析)。
容器檔案就是上面說到的Codec程式對圖片集進行編碼之後的產物,被Codec編碼之後,除了必要的視訊音訊資訊之外,它還有一些其他的資訊。
我畫了一個草圖,解釋了一個經典的MP4容器結構是啥樣。。。
裡面提到了Track(軌道),這是一個專業術語,用來區分不同的音視訊/文字資料 但是MP4檔案裡面最重要的卻是這個MetaData,它包含了很多關於視訊的原始資料,比如視訊的大小,視訊的時長,還有一個索引表,這個索引表包含了不同軌道的起始位置(以位元組為單位),又因為每個軌道會被分成若干塊sample(取樣,每一塊取樣都是可以單獨被播放器播放的一段資料,以微妙為單位),metadata也會維護一個細粒度更小的索引表,記錄了每一塊sample的大小,起始位置,對應視訊的時間是多少(以位元組為單位)等等的資訊。
舉個簡單的例子,有些電影包含粵語,國語兩個聲道。我們想換聲道的時候會告訴播放器,我想聽粵語,那麼播放器會去索引表查詢粵語的軌道起始位置,並且源源不斷的讀取粵語音軌的資料並播放出來。這也解釋了為何上圖會有兩個audio track。
在接下來的章節我會詳細介紹播放器是怎麼解析容器檔案,這裡大家只需要知道大概就好。
3. 視訊處理的流程-從後臺到前端
從一個實際的流程出發,
導演用膠片拍攝了原片(Raw Data),膠片就代表著原始檔案,也就是圖片集(因為膠片就是一幀一幀的連續圖片),使用軟體把原始檔編碼(Encode)成容器檔案(Container),之後可能為了不容解析度的原因,還需要將原始的高清容器,轉換成不同的解析度的容器檔案,對應圖中的process這一步。最後在放在伺服器或者CDN上,又播放器將其下載播放。
補充一張圖。
華麗麗的分割線
ok,這次分享就結束了,我會在下次分享詳細介紹播放器是怎麼解析,讀取容器檔案,同時也會深入的介紹一下MP4容器的一些格式規範,有助於大家去分析開源播放器的原始碼。