Android系統中音視頻播放技術探究
作者 | 戶銳,單位:中國移動智慧家庭運營中心
?Labs 導讀
隨著智能手機和5G技術的普及,視頻播放需求迅速增加,碎片時間刷小視頻,熬夜追電視劇都是視頻播放,毫不夸張地說,視頻播放時刻伴隨著你和我。我們經常聽別人說MP4、MKV、H264、H265、AAC、1080p、60fps等一些專業術語,他們的含義是什么呢?視頻播放的流程是怎么樣的呢?當今占市場份額最大的Android平臺播放器框架是如何設計的呢?本文就帶你一起捋一捋這些知識要點。
Part 01 常見的專業術語
我們通常說的MP4、MKV、WMV是一種視頻文件格式,在行業中我們將其稱為容器,音視頻文件的數據存放在容器中,每種容器都有固定的格式。其中MP4是最常見的國際通用格式,在常見的播放軟件中都可以使用和播放,被廣泛使用,在安卓手機上用相機錄制的視頻一般都是MP4格式。MKV最大的特點就是能容納多種不同類型編碼的視頻、音頻及字幕流,俗稱萬能媒體容器。WMV是微軟推出的一種流媒體格式,它是在ASF格式升級延伸來的。在同等視頻質量下,WMV格式的體積非常小,因此很適合在網上播放和傳輸,通過工具或者命令將WMV文件轉成相同分辨率的MP4文件后,文件的大小會變大。下圖可以粗略的表示文件格式和數據的關系。
視頻的原始數據是YUV格式,音頻的原始數據是PCM格式,這兩種格式的數據會占用大量的存儲空間。為了解壓音視頻數據占用的存儲空間,需要將音視頻數據進行壓縮,這就是行業中說的編碼,在播放音視頻文件的時候需要將壓縮的音視頻文件進行解壓縮,這就是解碼。編碼和解碼都是按照一定規范進行的,不同的規范有不同的名字,比如H264、H265、AAC。換言之H264、H265、AAC就是編解碼格式。其中H265和H264都是視頻編解碼格式,且都是基于宏塊進行編碼,其中H264最大支持16*16的宏塊,而H265最大支持64*64的宏塊,因此H265在細節表達上會比H264更清楚,在像素一致的情況下,H265的壓縮比會比H264更高。由于H265具有更高的壓縮比,所以H265占據的存儲空間更少,從而達到了節約帶寬的目的和播放流暢的效果,這也是目前熱播高清電視劇采用H265編碼的原因。
我們經常聽到的畫面比例是指視頻畫面寬和高的比例。生活中常見的比例有16:9和4:3。我們還常常聽到標清、高清、超高清等術語,這對應的專業術語是分辨率,720p以下為標清,720p、1080p為高清,4k、8k稱為超高清。720p、1080p究竟是什么意思呢?說到這里,我們要先講一下視頻分辨率的概念,分辨率指視頻寬高的像素數值,單位為Px。通常視頻分辨率的數值寬高比要等于畫面比例,不然視頻文件就會產生黑邊。標準1080p的分辨率為1920×1080其含義是寬度上有1920個像素,高度上有1080個像素,分辨率越高視頻就越清晰。而30fps、60fps是指幀率,視頻是由一張一張的圖片組成的,視頻播放就是將一張一張的圖片(一張圖片也可以簡單理解為一幀)按照固定的速率展示給觀眾,比如一秒鐘顯示30幀(30fps),或者一秒鐘顯示60幀(fps),讓觀眾感覺動作是連續的。因此幀率就是為每秒顯示幀數,幀率越高視頻就越流暢,目前主流的視頻幀率是60幀。
目前主流的安卓系統都支持H264、H265硬件編碼和解碼,可以很好滿足用戶的需求。而且在安卓系統上為開發人員預留了方便簡單的接口來實現編碼和解碼,比如用MediaRecorder實現錄像(編碼場景),用MediaPlayer實現播放(解碼場景),MediaRecorder和MediaPlayer接口非常簡單,上手容易,而且屏蔽了編解碼底層邏輯,對開發人員非常友好。接下來我們簡單介紹一下視頻播放的流程。
Part 02 視頻播放流程
一個播放器播放視頻的主要流程如下:
1.讀取視頻文件解析文件格式,即獲取容器格式,在安卓平臺Media框架的DataSource有一個sniff函數,此函數會調用各個Extractor的sniff函數,每個Extractor的sniff函數會返回一個分數,DataSource最終會選擇分數最大的Extractor;
2.利用對應的容器格式解析器(在Android平臺的名字是Extractor)對視頻文件進行解析,獲取元數據、音軌、視頻軌索引以及音視頻編碼器格式,如果是MP4文件,在安卓平臺就會使用Mp4Extractor對文件進行解析;
3.調用對應的解碼器對音頻和視頻數據進行解碼,在安卓平臺就是通過MediaCodec調用OMX或者C2解碼器插件進行解碼,并將解碼后的數據通過MediaCodec返回;
4.對解碼后的數據進行音視頻同步,必要時做丟幀處理,在做音視頻同步的時候一般都是視頻同步音頻,而且在安卓平臺也是這么做的,具體做法是將解碼后視頻的時間戳和音頻時間戳進行比較,如果視頻時間戳和音頻時間戳差值大于某個設定的值比如200ms,那么就丟棄當前視頻幀;
5.對音視頻進行渲染,在安卓平臺上解碼器解碼后的音頻數據會交給SurfaceFlinger渲染,解碼后的音頻數據會通過AudioTrack處理最終輸出到揚聲器。
現在我們大概了解了一個視頻播放的主要流程,但是作為一名勤勞的搬磚人,總是想自己編寫一個視頻播放器,體驗一下自己的成果,下面就簡單介紹一下在Android平臺上如何編寫一個簡單的視頻播放器。
Part 03 Android上實現一個最簡單的播放器
其實在Android想要編寫一個視頻播放器,是非常簡單的。利用Android提供的一個MediaPlayer Java類,可以很容易實現一個播放器。
Sample Code:
String url = https://www.xxx.com/video/test.mp4
MediaPlayer player = new MediaPlayer();
player.setDataSource(url);
player.prepare();
player.setDisplay(surfaceView.getHolder());
player.start();
你沒有看錯,就是這么簡單。
作為一名愛鉆研技術的伙伴,你肯定很好奇,Android MediaPlayer內部是如何實現的呢?
Part 04 Android MeiaPlayer播放器架構
在Android平臺上Java層的MediaPlayer只是提供對外暴露的接口,其實真正的邏輯實現都在Native的MediaSever中。MediaPlayer的setDataSource會觸發Native IPC請求服務端創建一個player實例,而prepare會觸發服務端尋找一個合適的容器解析器(MediaExtractor),并解析得到需要的解碼器信息,因此prepare比較耗時start會觸發服務端創建對應的解碼器,并開始解碼,然后音視頻同步,最后顯示。
MediaCodec可以認為是一個解碼器組件與OMX或者C2解碼器plugin交互。
在onInputBufferAvailable回調中給解碼器喂數據,通過queueInputBuffer向解碼器提供數據。
在onOutputBufferAvailable回調中處理解碼后的數據,通過releaseOutputBuffer規劃output buffer給解碼器。
在Android平臺上,除了MediaPlayer外還有很多開源的播放器框架可以供我們使用,下面我們用一個表格簡單介紹一下。
Part 05 常見開源播放器
Part 06 安卓音視頻的未來
音視頻技術在數字化時代永遠不會過時,而且需求會越來越旺盛。我們工作中參加視頻會議,生活中刷小視頻,拿著手機追劇,微信視頻通話,進出大樓的人臉識別等,都與音視頻技術密切相關。隨著5G技術的發展和普及,視頻場景越來越多。同時隨著元宇宙概念的火熱,VR、AR被推向風口浪尖,而VR、AR都與音視頻密切相關,目前市面上的VR一體機基本是安卓系統。筆者相信會有更多的音視頻應用場景出現,音視頻技術也必將為人類的數字生活增添更多色彩。?