一. 音視頻采集流程
串聯(lián)整個(gè)音視頻錄制流程,完成音視頻的采集、編碼、封包成 mp4 輸出。

通過(guò)攝像頭和麥克風(fēng)獲得實(shí)時(shí)的音視頻數(shù)據(jù);
- 播放流程: 獲取流—>解碼—>播放。
- 錄制播放路程: 錄制音頻視頻—>視頻處理—>編碼—>上傳服務(wù)器->別人播放。
- 直播過(guò)程 : 錄制音視頻—>編碼—>流媒體傳輸—>服務(wù)器—>流媒體傳輸?shù)狡渌蛻舳恕?gt;解碼—>播放。
視頻采樣數(shù)據(jù) : 一般都是 YUV 或 RGB 格式。
音頻采樣數(shù)據(jù) :一般都是PCM格式。

二.音頻采集
1.Android如何采集音頻
Android SDK對(duì)于音頻采集提供兩套API:MediaRecorder和AudioRecorder。
AudioRecord
AudioRecord輸出是PCM語(yǔ)音數(shù)據(jù),得到原始的一幀幀PCM音頻數(shù)據(jù)。如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實(shí)現(xiàn)數(shù)據(jù)編碼以及壓縮。
一般直播技術(shù)采用的就是 AudioRecorder 采集音頻數(shù)據(jù)。
PCM(Pulse Code Modulation)也被稱為脈沖編碼調(diào)制。PCM音頻數(shù)據(jù)是未經(jīng)壓縮的音頻采樣數(shù)據(jù)裸流,它是由模擬信號(hào)經(jīng)過(guò)采樣、量化、編碼轉(zhuǎn)換成的標(biāo)準(zhǔn)的數(shù)字音頻數(shù)據(jù)。
MediaRecorder
MediaRecorder是偏上層的一個(gè)API,可以直接把手機(jī)麥克風(fēng)錄入的音頻數(shù)據(jù)進(jìn)行編碼壓縮為AMR,MP3等并保存文件。
MediaRecorder和AudioRecord的區(qū)別
- MediaRecorder和AudioRecord都可以錄制音頻,區(qū)別是MediaRecorder錄制的音頻文件是經(jīng)過(guò)壓縮后的,需要設(shè)置編碼器。并且錄制的音頻文件可以用系統(tǒng)自帶的Music播放器播放。而AudioRecord錄制的是PCM格式的音頻文件,需要用AudioTrack來(lái)播放,AudioTrack更接近底層,PCM經(jīng)過(guò)編碼壓縮可以為 amr MP3 AAC。
- 當(dāng)要簡(jiǎn)單的把數(shù)據(jù)采集為音頻文件,就使用MediaRecorder,如果要對(duì)音頻做進(jìn)一步的算法處理就使用AudioRecorder。
MediaRecorder和AudioRecord的優(yōu)缺點(diǎn):
AudioRecord:
主要是實(shí)現(xiàn)邊錄邊播以及對(duì)音頻的實(shí)時(shí)處理,這個(gè)特性讓他更適合在語(yǔ)音方面有優(yōu)勢(shì);
優(yōu)點(diǎn):語(yǔ)音的實(shí)時(shí)處理,可以用代碼實(shí)現(xiàn)各種音頻的封裝。
缺點(diǎn):輸出是PCM格式文件,如果保存成音頻文件,是不能夠被播放器播放的,所以必須先寫代碼實(shí)現(xiàn)數(shù)據(jù)編碼以及壓縮。
MediaRecorder:
已經(jīng)集成了錄音、編碼、壓縮等,支持少量的錄音音頻格式,大概有,aac,amr,3gp等
優(yōu)點(diǎn):集成,直接調(diào)用相關(guān)接口即可,代碼量小
缺點(diǎn):無(wú)法實(shí)時(shí)處理音頻;輸出的音頻格式不是很多,例如沒(méi)有輸出mp3格式文件
MediaRecorder和AudioRecord的應(yīng)用:
如果只是想簡(jiǎn)單地做一個(gè)錄音機(jī),錄制音頻文件,就使用 MediaRecorder,而如果需要對(duì)音頻做進(jìn)一步的算法處理、或者采用第三方的編碼庫(kù)進(jìn)行壓縮、以及網(wǎng)絡(luò)傳輸、直播等應(yīng)用,則建議使用 AudioRecord。
三.視頻采集
和音頻一樣,也有高層和低層的 API,高層就是Camera 和 MediaRecorder,可以快速實(shí)現(xiàn)編碼,低層就是直接使用Camera,然后將采集的數(shù)據(jù)進(jìn)行濾鏡、降噪等前處理,處理完成后由 MediaCodec 進(jìn)行硬件編碼,最后采用 MediaMuxer 生成最終的視頻文件。
在 Android 系統(tǒng)下有兩套 API 可以進(jìn)行視頻采集,Camera 和 Camera2。Camera是以前老的 API ,從 Android 5.0(21)之后就已經(jīng)放棄了。如今主要使用 Camera2 進(jìn)行視頻的采集。
直播開發(fā)中經(jīng)常需要獲取視頻原始幀數(shù)據(jù)然后前置處理例如:美顏、水印、特效等然后通過(guò)編碼在通過(guò)rtmp或者rtsp等協(xié)議方式推流出去,可以完成實(shí)時(shí)圖像傳遞。
那么如何獲取原始視頻幀數(shù)據(jù)?android camera api有一個(gè)設(shè)置回調(diào)的方法,可以將可以通過(guò)它來(lái)獲取原始視頻數(shù)據(jù)如nv21 、 nv12 、 yv12 等。

MediaRecorder實(shí)現(xiàn)視頻采集優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
使用方便,得到就是編碼和封裝好的音視頻文件,可以直接使用。
缺點(diǎn):
無(wú)法獲取原始數(shù)據(jù),從而無(wú)法對(duì)原始數(shù)據(jù)添加一些自己的處理。
Camera實(shí)現(xiàn)視頻采集步驟
- 通過(guò)MediaCodec創(chuàng)建一個(gè)用于輸入的Surface
- 通過(guò)通過(guò)camera預(yù)覽時(shí)的上下文EGL創(chuàng)建OpenGL的環(huán)境,根據(jù)上面得到的Surface創(chuàng)建EGLSuface。
- 通過(guò)camera預(yù)覽時(shí)的綁定的紋理id,進(jìn)行紋理繪制。
- 交換數(shù)據(jù),讓數(shù)據(jù)輸入新Surface。使用AudioReocod進(jìn)行聲音的采集
- 通過(guò)Mediacodec編碼為h264、AAC。
- 通過(guò)MediaMuxer進(jìn)行數(shù)據(jù)封裝為mp4。
四. 視頻處理
視頻或者音頻完成采集之后得到原始數(shù)據(jù),為了增強(qiáng)一些現(xiàn)場(chǎng)效果或者加上一些額外的效果,我們一般會(huì)在將其編碼壓縮前進(jìn)行處理,例如:視頻美顏及變聲等操作。
1. 音頻處理
可以對(duì)音頻的原始流做處理,如降噪、回音、以及各種 filter 效果。
2. 視頻處理
現(xiàn)在抖音、美圖秀秀等,在拍攝,視頻處理方面,都提供了很多視頻濾鏡,而且還有各種貼紙、場(chǎng)景、人臉識(shí)別、特效、添加水印等。
對(duì)視頻進(jìn)行美顏和添加特效大部分都是通過(guò) OpenGL 進(jìn)行處理的。Android 中有 GLSurfaceView,這個(gè)類似于 SurfaceView,不過(guò)可以利用 Renderer 對(duì)其進(jìn)行渲染。通過(guò) OpenGL 可以生成紋理,通過(guò)紋理的 Id 可以生成 SurfaceTexture,而 SurfaceTexture 可以交給 Camera,最后通過(guò)紋理就將攝像頭預(yù)覽畫面和 OpenGL 建立了聯(lián)系,從而可以通過(guò) OpenGL 進(jìn)行一系列的操作。
美顏的整個(gè)過(guò)程無(wú)非是根據(jù) Camera 預(yù)覽的紋理通過(guò) OpenGL 中 FBO 技術(shù)生成一個(gè)新的紋理,然后在 Renderer 中的onDrawFrame() 使用新的紋理進(jìn)行繪制。添加水印也就是先將一張圖片轉(zhuǎn)換為紋理,然后利用 OpenGL 進(jìn)行繪制。添加動(dòng)態(tài)掛件特效則比較復(fù)雜,先要根據(jù)當(dāng)前的預(yù)覽圖片進(jìn)行算法分析識(shí)別人臉部相應(yīng)部位,然后在各個(gè)相應(yīng)部位上繪制相應(yīng)的圖像,整個(gè)過(guò)程的實(shí)現(xiàn)有一定的難度,人臉識(shí)別技術(shù)目前有 OpenCV、Dlib、MTCNN 等。
各種美顏和視頻添加特效的簡(jiǎn)單效果也可以基于GPUImage框架實(shí)現(xiàn)。
3. 紋理
紋理是表示物體表面的一幅或幾幅二維圖形,也稱紋理貼圖(texture)。當(dāng)把紋理按照特定的方式映射到物體表面上的時(shí)候,能使物體看上去更加真實(shí)。當(dāng)前流行的圖形系統(tǒng)中,紋理繪制已經(jīng)成為一種必不可少的渲染方法。在理解紋理映射時(shí),
可以將紋理看做應(yīng)用在物體表面的像素顏色。在真實(shí)世界中,紋理表示一個(gè)對(duì)象的顏色、圖案以及觸覺(jué)特征。紋理只表示對(duì)象表面的彩色圖案,它不能改變對(duì)象的幾何結(jié)構(gòu)。
4. OpenGL ES
OpenGL ES 是手機(jī)、PDA 和游戲主機(jī)等嵌入式設(shè)備三維 (二維也包括) 圖形處理的 API,當(dāng)然是用來(lái)在嵌入式設(shè)備上的圖形處理了,OpenGL ES 強(qiáng)大的渲染能力使其成為我們?cè)谇度胧皆O(shè)備上進(jìn)行圖形處理的優(yōu)良選擇。我們經(jīng)常使用的場(chǎng)景有:
圖片處理。比如圖片色調(diào)轉(zhuǎn)換、美顏等。
攝像頭預(yù)覽效果處理。比如美顏相機(jī)、惡搞相機(jī)等。
視頻處理。攝像頭預(yù)覽效果處理可以,這個(gè)自然也不在話下了。
3D 游戲。比如神廟逃亡、都市賽車等。
五.音視頻編碼和封裝
1. 為何要對(duì)音視頻進(jìn)行編碼?
音視頻的原始數(shù)據(jù)非常龐大,難以存儲(chǔ)和傳輸。要解決音視頻數(shù)據(jù)的存儲(chǔ)和傳輸問(wèn)題,或是為了加密等。
就需要對(duì)這些數(shù)據(jù)進(jìn)行壓縮,音視頻數(shù)據(jù)壓縮技術(shù)就是音視頻編碼。
編碼的目的就是在最小圖像或音頻信息丟失情況下得到最大的壓縮,解碼是相對(duì)編碼的,其目的是最大限度的還原原始圖像或聲音信息。
編解碼的意義就是便于數(shù)據(jù)傳輸和存儲(chǔ)。
2. 編解碼種類(硬件編碼,軟件編碼)
軟編碼:使用CPU進(jìn)行編碼,實(shí)現(xiàn)直接、簡(jiǎn)單,參數(shù)調(diào)整方便,升級(jí)易,但CPU負(fù)載重,性能較硬編碼低,低碼率下質(zhì)量通常比硬編碼要好一點(diǎn)。
硬編碼:使用非CPU進(jìn)行編碼,如顯卡GPU、專用的DSP、FPGA、ASIC
芯片等,性能高,低碼率下通常質(zhì)量低于軟編碼器,但部分產(chǎn)品在GPU硬
件平臺(tái)移植了優(yōu)秀的軟編碼算法(如X264)的,質(zhì)量基本等同于
軟編碼。軟解碼,指利用CPU的計(jì)算能力來(lái)解碼,通常如果CPU的能力不是很強(qiáng)的時(shí)候,一則解碼速度會(huì)比較慢,二則手機(jī)可能出現(xiàn)發(fā)熱現(xiàn)象。優(yōu)點(diǎn)是,由于使用統(tǒng)一的算法,兼容性會(huì)很好。
硬解碼,指的是利用手機(jī)上專門的解碼芯片來(lái)加速解碼。通常硬解碼的解碼速度會(huì)快很多,但是由于硬解碼由各個(gè)廠家實(shí)現(xiàn),質(zhì)量參差不齊,非常容易出現(xiàn)兼容性問(wèn)題。
在Android 4.1之前沒(méi)有提供硬編解碼的API,所以基本都是采用開源的那些庫(kù),比如著名的FFMpeg實(shí)現(xiàn)軟編解碼。通常情況下,同一平臺(tái)同一硬件環(huán)境,硬編碼的速度快于軟件編碼,軟編碼使用CPU來(lái)進(jìn)行計(jì)算,會(huì)消耗一些app的運(yùn)算效率。在Android4.1及以上版本可以使用MediaCodec來(lái)訪問(wèn)底層的媒體編解碼器從而支持硬編碼/硬解碼。
Android API 中有個(gè) MediaCodec 的類,利用 MediaCodec 可實(shí)現(xiàn)硬編碼,高效且方便,Android API 中還有個(gè)叫 MediaMuxer 的類,可以實(shí)現(xiàn)音頻與視頻的合成,但是 MediaCodec 使用的 API 最低要求是 16,MediaMuxer 則是 18,如果使用軟編碼,那么 API 限制將不再那么苛刻。
推薦安卓4.1以上使用硬編碼,以下使用軟編碼,而iOS使用全部硬編碼。如果是使用播放解碼,不管是安卓還是iOS,都使用軟解碼方案,雖然這樣做不可避免的犧牲功耗,但是在部分細(xì)節(jié)方面表現(xiàn)會(huì)較優(yōu),且可控性強(qiáng),兼容性也強(qiáng),出錯(cuò)情況少。
3. 視頻編碼封裝的可行性方案
第一個(gè)就是大家熟知的ffmpeg,將ffmpeg移植到anroid平臺(tái),編譯成so文件,由jni 調(diào)用,可以實(shí)現(xiàn)音視頻的分離、裁剪、拼合、加字幕、濾鏡等功能。
第二個(gè)就是android 自帶的MediaCodec 框架,MediaCodec框架底層調(diào)用的是StageFright庫(kù),StageFright庫(kù)是默認(rèn)封裝在android系統(tǒng)里面的。
第三個(gè),如果只是做視頻音頻混合的話,可以用這個(gè)開源工程mp4parser使用MediaCodec 類進(jìn)行編碼壓縮,視頻壓縮為H.264,音頻壓縮為aac,使用MediaMuxer 將音視頻合成為MP4。
4. 可行性方案的優(yōu)缺點(diǎn)
功能多少方面:
ffmpeg 無(wú)疑排第一位,他集合了視頻編解碼、視頻濾鏡、流媒體推流、音頻各種特效等等,基本上你能想到的功能都在里面。
第二位當(dāng)是Android的親兒子,MediaCodec。MediaCodec涵蓋了音視頻解復(fù)用、音頻解碼、視頻解碼、音頻編碼、視頻編碼、音視頻合并的整個(gè)流程。跟ffmpeg相比,MediaCodec 更接近底層硬件。這個(gè)方案如果想要實(shí)現(xiàn)視頻的濾鏡、字幕、拼接等功能的話,需要自己配合OpenGL ES 來(lái)實(shí)現(xiàn),另外,音視頻拼接的話,要考慮到不同音頻采樣率的重采樣問(wèn)題,音頻重采用問(wèn)題,需要懂得傅立葉變換相關(guān)的離散信號(hào)變換方法,如果要實(shí)現(xiàn)音頻特效,如變聲、均衡器的話,也需要懂得上述信號(hào)變換方法。因此,很少公司會(huì)采用。mp4praser,可以實(shí)現(xiàn)音視頻編解碼及編輯。
學(xué)習(xí)門檻:
如果只是做視頻轉(zhuǎn)碼、加文字、圖片特效等,ffmpeg和MediaCodec 旗鼓相當(dāng),mp4parser最低(但是基于mp4parser的資料比較少,其實(shí)也未必)。如果是要拼接視頻、做音頻的變聲、均衡器特效的話,MediaCodec是難度最高的,因?yàn)檫@一切需要你從底層原理做起。
運(yùn)行效率:
MediaCodec硬解硬編最快,ffmpeg硬解硬編方案稍慢(注意,2017年5月以后最新版ffmpeg已經(jīng)整合了MediaCodec,不再慢了),mp4parser(只能軟解軟編)最慢。
穩(wěn)定性:
MediaCodec和ffmpeg 的硬解硬編方案旗鼓相當(dāng),mp4parser在低配的機(jī)器上可能出現(xiàn)卡頓的問(wèn)題。
打包占用空間:
國(guó)內(nèi)最得最好的ffmpeg硬解硬編方案,其so文件在10+M,MediaCodec由于是純java 代碼,占用空間很容易做到幾百K甚至幾十K。mp4parser也是純Java,開發(fā)包同樣非常小。
5. FFmpeg
ffmpeg 是基于C語(yǔ)言的著名視頻編解碼方案。具有非常強(qiáng)大的功能包括視頻采集功能、視頻格式轉(zhuǎn)換、視頻抓圖、給視頻加水印等。國(guó)內(nèi)有也有不少的公司將ffmpeg 移植到iOS和android 平臺(tái)進(jìn)行視頻處理,例如,美拍、秒拍等。當(dāng)前眾多的視頻SDK中, 大都是封裝ffmpeg對(duì)視頻進(jìn)行轉(zhuǎn)碼, 壓縮, 裁剪的處理。優(yōu)點(diǎn)是ffmpeg發(fā)展到現(xiàn)在已經(jīng)相對(duì)成熟, 支持的視頻格式較多。但是缺點(diǎn)有:
- 速度慢,用cpu來(lái)執(zhí)行視頻數(shù)據(jù)的處理屬于軟解碼, 效率并不高;
- 增加包的體積,一般好的sdk(如阿里云短視頻sdk) 有20m上下, 這樣的sdk合入應(yīng)用后, 對(duì)應(yīng)用大小有一定的影響。
FFmpeg本質(zhì)上可以看做是媒體處理工具的集合,包含了很多的媒體文件處理工具,例如媒體文件格式解析工具、編解碼器等,這些工具實(shí)際上就是一個(gè)個(gè)的庫(kù),而FFmpeg的命令行程序?qū)嶋H上就是對(duì)這些庫(kù)的一種包裝,在調(diào)用命令行程序時(shí)也是通過(guò)底下的這些庫(kù)來(lái)完成操作。這些庫(kù)有的是編譯時(shí)可選的,而且FFmpeg也支持一些外部的庫(kù),例如x264、MediaCodec。FFmpeg由于提供了很多的編解碼器,而且它的媒體操作也很豐富,所以可以支持非常多的媒體類型,同時(shí)很多的處理功能也已經(jīng)由FFmpeg提供,使用者只需要去調(diào)用即可,所以不少的編輯處理功能可以相對(duì)簡(jiǎn)單地完成開發(fā)。
適用場(chǎng)景:多平臺(tái)使用(例如不同芯片廠商的手機(jī)),短時(shí)間攝像。
6. MediaCodec
MediaCodec提供的功能就相對(duì)單一,它基本上只用來(lái)完成編解碼相關(guān)的功能。以整個(gè)視頻轉(zhuǎn)碼流程舉例,大致需要幾個(gè)步驟:解封裝->解碼->濾鏡處理等操作->編碼->封裝,MediaCodec只提供編解碼功能,而其它的功能則需要其它組件,如MediaExtractor以及MediaMuxer來(lái)完成。但是MediaCodec在編解碼時(shí)提供硬件編解碼功能,其好處是非常明顯的,效率很高,且CPU占用大幅降低。如果不使用硬件編解碼的話,很多的轉(zhuǎn)碼過(guò)程的時(shí)長(zhǎng)實(shí)在長(zhǎng)得是令人無(wú)法忍受,放到APP上簡(jiǎn)直就是無(wú)法使用的功能。畢竟一段很短的視頻,轉(zhuǎn)碼要好幾分鐘,發(fā)燙還嚴(yán)重,體驗(yàn)肯定是不行的。MediaCodec的缺點(diǎn)就是一定程度上會(huì)依賴于設(shè)備,由于MediaCodec的硬解碼實(shí)際上是由廠商所提供的,同時(shí)安卓設(shè)備的硬件相互之間差異很大,所以在硬解碼實(shí)現(xiàn)上自然也有所差別,就導(dǎo)致了一樣的程序,一些設(shè)備上可以正常跑,而在另一些設(shè)備上則可能會(huì)出問(wèn)題,此時(shí)就需要自行提供兼容性上的支持。
適用場(chǎng)景:有固定的硬件方案,無(wú)需移植(例如智能家具產(chǎn)品),需要長(zhǎng)時(shí)間攝像。
7. FFmpeg和MediaCodec對(duì)比
作一個(gè)簡(jiǎn)單的比喻:FFmpeg就像一個(gè)工具箱,而MediaCodec就像一類功能強(qiáng)大,但是使用范圍相對(duì)受限且不夠靈活的工具。
- 1.FFmpeg也有對(duì)MediaCodec的支持,在編譯出合適的庫(kù)后,可以通過(guò)FFmpeg的api來(lái)調(diào)用MediaCodec,但只能使用解碼功能。
- 2.MediaCodec并非只代表硬編解碼,它事實(shí)上可以看做是一種服務(wù),廠商將自己的編解碼方案預(yù)先注冊(cè)于服務(wù)中,而用戶在需要時(shí)再通過(guò)服務(wù)去調(diào)用相應(yīng)的編解碼器來(lái)完成任務(wù)。MediaCodec支持硬件編解碼以及軟件編解碼,可以自行選擇需要使用的編解碼器。
- 3.FFmpeg在使用MediaCodec時(shí),使用的方式和JAVA調(diào)用是類似的,F(xiàn)Fmpeg會(huì)通過(guò)JNI的callXXmethod去調(diào)用MediaCodec的方法,這個(gè)過(guò)程其實(shí)和JAVA中的調(diào)用沒(méi)有區(qū)別,但是FFmpeg通過(guò)封裝MediaCodec的操作,使得MediaCodec可以按照FFmpeg的編解碼流程進(jìn)行調(diào)用。
- 4.MediaCodec它本身并不是Codec,它是通過(guò)調(diào)用底層編解碼組件具有Codec能力。
8. 開源方案
基于ffmpeg 的免費(fèi)軟解軟編方案在github.com有很多,例如:EpMedia,硬解硬編方案還沒(méi)有看到。商業(yè)收費(fèi)的方案有趣拍、美攝等。不過(guò)這些商業(yè)方案是按年收費(fèi)的有點(diǎn)小貴。
基于MediaCodec 的免費(fèi)開源方案有m4m,videotranscoder等,不過(guò)這些開源方案,表面看上去功能很強(qiáng)大,實(shí)際使用的時(shí)候會(huì)遇到不少坑,只適用于對(duì)MediaCodec的原理進(jìn)行研究。
六.音視頻解碼

解協(xié)議的作用,就是將流媒體協(xié)議的數(shù)據(jù),解析為標(biāo)準(zhǔn)的相應(yīng)的封裝格式數(shù)據(jù)。視音頻在網(wǎng)絡(luò)上傳播的時(shí)候,常常采用各種流媒體協(xié)議,例如HTTP,RTMP,或是MMS等等。這些協(xié)議在傳輸視音頻數(shù)據(jù)的同時(shí),也會(huì)傳輸一些信令數(shù)據(jù)。這些信令數(shù)據(jù)包括對(duì)播放的控制(播放,暫停,停止),或者對(duì)網(wǎng)絡(luò)狀態(tài)的描述等。解協(xié)議的過(guò)程中會(huì)去除掉信令數(shù)據(jù)而只保留視音頻數(shù)據(jù)。例如,采用RTMP協(xié)議傳輸?shù)臄?shù)據(jù),經(jīng)過(guò)解協(xié)議操作后,輸出FLV格式的數(shù)據(jù)。
1. 解封裝
解封裝的作用,就是將輸入的封裝格式的數(shù)據(jù),分離成為音頻流壓縮編碼數(shù)據(jù)和視頻流壓縮編碼數(shù)據(jù)。封裝格式種類很多,例如MP4,MKV,RMVB,TS,F(xiàn)LV,AVI等等,它的作用就是將已經(jīng)壓縮編碼的視頻數(shù)據(jù)和音頻數(shù)據(jù)按照一定的格式放到一起。例如,F(xiàn)LV格式的數(shù)據(jù),經(jīng)過(guò)解封裝操作后,輸出H.264編碼的視頻碼流和AAC編碼的音頻碼流。
2. 解碼
解碼的作用,就是將視頻/音頻壓縮編碼數(shù)據(jù),解碼成為非壓縮的視頻/音頻原始數(shù)據(jù)。音頻的壓縮編碼標(biāo)準(zhǔn)包含AAC,MP3,AC-3等等,視頻的壓縮編碼標(biāo)準(zhǔn)則包含H.264,MPEG2,VC-1等等。解碼是整個(gè)系統(tǒng)中最重要也是最復(fù)雜的一個(gè)環(huán)節(jié)。通過(guò)解碼,壓縮編碼的視頻數(shù)據(jù)輸出成為非壓縮的顏色數(shù)據(jù),例如YUV420P,RGB等等;壓縮編碼的音頻數(shù)據(jù)輸出成為非壓縮的音頻抽樣數(shù)據(jù),例如PCM數(shù)據(jù)。
3. 音頻同步
視音頻同步的作用,就是根據(jù)解封裝模塊處理過(guò)程中獲取到的參數(shù)信息,同步解碼出來(lái)的視頻和音頻數(shù)據(jù),并將視頻音頻數(shù)據(jù)送至系統(tǒng)的顯卡和聲卡播放出來(lái)。
4. 硬解碼和軟解碼
硬解
字面上理解就是用硬件解碼。通過(guò)顯卡的視頻加速功能對(duì)高清視頻進(jìn)行解碼??梢岳斫鉃橛幸粋€(gè)專門的電路板來(lái)進(jìn)行視頻的解碼工作,是依靠GPU。
調(diào)用GPU的專門模塊編碼來(lái)解碼,減少CPU運(yùn)算。顯卡核心GPU擁有獨(dú)特的計(jì)算方法,解碼效率非常高,這樣不但能夠減輕CPU的負(fù)擔(dān),還有著低功耗,發(fā)熱少等特點(diǎn)。
但是,由于硬解碼起步比較晚,軟件和驅(qū)動(dòng)對(duì)他的支持度很低,基本上硬解碼內(nèi)置什么樣的模塊,就解碼什么樣的視頻,面對(duì)網(wǎng)上各色各樣的視頻編碼樣式,兼容性不好。此外,硬解碼的濾鏡、字幕、畫質(zhì)方面都做的不夠理想。
對(duì)于android設(shè)備,目前用得比較多的芯片就是高通、海思和聯(lián)發(fā)科,這些芯片大都集成了很多的功能,CPU、GUP、DSP、ISP包括視頻解碼、音頻解碼等等。
在Android中使用硬件解碼直接使用MediaCodec就可以了,雖然MediaPlayer也是硬件解碼,但是被封裝得太死了,支持的協(xié)議很少。而MediaCodec就很好拓展,我們可以根據(jù)流媒體的協(xié)議和設(shè)備硬件本身來(lái)自定義硬件解碼,代表播放器就是Google的ExoPlayer。
軟解
字面上理解就是用軟件解碼。但是實(shí)際上還是要硬件支撐。這個(gè)硬件就是CPU。
在軟解碼過(guò)程中,需要對(duì)大量的視頻信息進(jìn)行運(yùn)算,所以對(duì)CPU性能的要求非常高。尤其是對(duì)高清大碼率的視頻來(lái)說(shuō),巨大的運(yùn)算量就會(huì)造成轉(zhuǎn)換效率低,發(fā)熱量高等問(wèn)題。
我們最常見(jiàn)的視頻軟解碼開源庫(kù)就是FFmpeg。目前基于FFmpeg的開源播放器有B站的ijkplayer
不過(guò),軟解碼不需要過(guò)多的硬件支持,兼容性非常高,即使出現(xiàn)新的視頻編碼格式,只要安裝好相應(yīng)的解碼器文件,就可以順利播放。而且軟解碼擁有豐富的濾鏡,字幕,畫面處理優(yōu)化等效果,只有你CPU夠強(qiáng)悍,就能夠?qū)崿F(xiàn)更加出色的畫面效果。
5. 硬解和軟解總結(jié)
在Android設(shè)備硬件支持的情況下優(yōu)先使用Android設(shè)備的硬件解碼,減少CPU的占用,更加省電。
在Android設(shè)備硬解不支持的情況下選擇使用軟解碼,不管怎么樣,視頻至少能夠播放,具有更好的適應(yīng)性,但是增加了CPU的占用,更加費(fèi)電,軟硬結(jié)合才是最好。
七. Android平臺(tái)音視解碼播放器選擇
在Android中播放視頻很簡(jiǎn)單,可以使用MediaPlayer+SurfaceView或者VideoView設(shè)置一個(gè)視頻文件路徑就可以實(shí)現(xiàn)播放了。但是如果想對(duì)音視頻再進(jìn)行處理,比如視頻播放過(guò)程中增加水印,或者對(duì)視頻進(jìn)行轉(zhuǎn)碼,就需要對(duì)視頻進(jìn)行編解碼處理了。
1. MediaPlayer
在Android系統(tǒng)中對(duì)于視頻播放器有原生的實(shí)現(xiàn)MediaPlayer, 以及將MediaPlayer,SurfaceView封裝在一起的VideoView, 兩者都只是使用硬解播放,基本上只支持本地和HTTP協(xié)議的視頻播放,擴(kuò)展性都很差,只適合最簡(jiǎn)單的視頻播放需求。
Android原生播放器,支持格式較少:支持mp4,3gp,資源文下支持mkv,使用比較簡(jiǎn)單,但是拓展性比較差。不需要集成第三方庫(kù),不占用apk體積。
2. ijkplayer
嗶哩嗶哩開源的基于ffmpeg開發(fā)的一款播放器,功能就比較強(qiáng)大了,如果只是使用它進(jìn)行播放,集成也較為簡(jiǎn)單,使用也和MediaPlayer差不多,但是要定制化需求,就有一定的門檻高度。支持軟硬編解碼,支持倍速播放,可以定制化集成需要的功能,集成占用體積也很小。
3. ExoPlayer(基本來(lái)自于官方文檔翻譯)
谷歌出品,推薦使用的播放器。同RecyclerView一樣定制化程度非常高。并加入了對(duì)DASH和HLS等直播協(xié)議的支持,但也只支持硬碼,如果項(xiàng)目中只需要支持對(duì)H264格式的視頻播放,以及流媒體協(xié)議比較常規(guī)(比如HTTP,HLS),基于ExoPlayer定制也是不錯(cuò)的選擇。
優(yōu)點(diǎn):
- 支持動(dòng)態(tài)的自適應(yīng)流HTTP(DASH) 和 平滑流,任何目前MediaPlayer支持的視頻格式(同時(shí)它還支持HTTP直播了(HLS),MP4,MP3,WebM,M4A,MPEG-TS 和 AAC).
- 支持高級(jí)的HLS特性,例如正確處理 EXT-X-DISCONTINUITY 標(biāo)簽。
- 無(wú)縫合并、連接和循環(huán)媒體的能力。
- 支持自定義使用場(chǎng)景。ExoPlayer專門為此設(shè)計(jì),它允許將許多組件替換為自定義實(shí)現(xiàn),它提供了低等級(jí)的媒體API,例如:MediaCodec,AudioTrack,MediaDrm,可以用于建立自定義媒體播放的解決方案。。以第三方依賴的方式集成,可以隨應(yīng)用升級(jí)版本。更少的適配性問(wèn)題,更少的設(shè)備特定的問(wèn)題和更少的行為變化, 在不同的設(shè)備和android的版本,可以接入ffmpeg。
缺點(diǎn):
- 相對(duì)于MediaPlayer更耗電:但是Android Q以開發(fā)audio affload,可以減低功耗。
- 最低API要求為16,早期版本不支持自動(dòng)檢查需要播放的媒體格式,后續(xù)的版本已經(jīng)支持。
4. 特性
功能支持情況
| 功能 | MediaPlayer | IjkPlayer | ExoPlayer |
|---|---|---|---|
| 調(diào)整顯示比例 | 支持 | 支持 | 支持 |
| 滑動(dòng)調(diào)節(jié)播放進(jìn)度、聲音、亮度 | 支持 | 支持 | 支持 |
| 雙擊播放、暫停 | 支持 | 支持 | 支持 |
| 重力感應(yīng)自動(dòng)進(jìn)入/退出全屏以及手動(dòng)進(jìn)入/退出全屏 | 支持 | 支持 | 支持 |
| 倍速播放 | 不支持 | 支持 | 支持 |
| 視頻截圖(使用 SurfaceView 時(shí)都不支持,默認(rèn)用的是 TextureView) | 支持 | 支持 | 支持 |
| 列表小窗全局懸浮播放 | 支持 | 支持 | 支持 |
| 連續(xù)播放一個(gè)列表的視頻 | 支持 | 支持 | 支持 |
| 廣告播放 | 支持 | 支持 | 支持 |
| 邊播邊緩存,使用了AndroidVideoCache 實(shí)現(xiàn) | 支持 | 支持 | 支持 |
| 彈幕,使用DanmakuFlameMaster 實(shí)現(xiàn) | 支持 | 支持 | 支持 |
| 多路播放器同時(shí)播放 | 支持 | 支持 | 支持 |
| 沒(méi)有任何控制 UI 的純播放 | 支持 | 支持 | 支持 |
| Android 8.0 畫中畫 | 支持 | 支持 | 支持 |
| 無(wú)縫銜接播放 | 支持 | 支持 | 支持 |
| 抖音 | 支持 | 支持 | 支持 |
協(xié)議/格式支持情況(只列舉常用格式/協(xié)議)
| 協(xié)議/格式 | MediaPlayer | IjkPlayer | ExoPlayer |
|---|---|---|---|
| https | 支持 | 支持 | 支持 |
| rtsp | 不支持 | 支持 | 不支持 |
| rtmp | 不支持 | 支持 | 支持 |
| ffconcat | 不支持 | 支持 | 不支持 |
| file(本地視頻) | 支持 | 支持 | 支持 |
| android.resource(raw) | 支持 | 支持 | 支持 |
| assets 中的視頻 | 支持 | 支持 | 支持 |
| mp4 | 支持 | 支持 | 支持 |
| m3u8 | 支持 | 支持 | 支持 |
| flv | 支持 | 支持 | 可播放,無(wú)法 seek 進(jìn)度 |
5. 建議
- 1.如果已知的播放場(chǎng)景比較簡(jiǎn)單,例如小視頻場(chǎng)景,都是mp4視頻(h264/aac格式),建議使用ExoPlayer,沒(méi)有比這更適合的;
- 2.涉及到多種視頻交互形式,直播、長(zhǎng)視頻等,還是建議引入ijkplayer等軟件的形式;
- 3.如果Android平臺(tái)不介意包大小,推薦使用VLC,VLC更新頻繁,官方維護(hù)相當(dāng)給力;如果比較關(guān)注包大小,建議選擇ijkplayer,ijkplayer目前的缺點(diǎn)是維護(hù)的不那么勤了;
- 4.長(zhǎng)遠(yuǎn)來(lái)看,國(guó)內(nèi)很多播放器都從接入ijkplayer開始,逐漸演化,去掉不適合自己產(chǎn)品的代碼,引入自己需要的module,漸漸變成自己的播放器;
6. 開源音視頻播放器UI方案
參考文章:
Android 音頻采集(原始音頻)
音視頻篇 - Android 音視頻涉及到的技術(shù)
Android音視頻編碼基礎(chǔ)一
微信 Android 視頻編碼爬過(guò)的那些坑
Android視頻技術(shù)探索之旅:美團(tuán)外賣商家端的實(shí)踐
Android音視頻開發(fā)之MediaCodec編解碼
Android視頻處理之MediaCodec-1-簡(jiǎn)介
Android視頻處理之MediaCodec-2-使用
Android視頻處理之MediaCodec-3-播放視頻
Android視頻處理之MediaCodec-4-視頻幀轉(zhuǎn)圖片
Android視頻處理之MediaCodec-5-生成mp4視頻
Android視頻處理之MediaCodec-6-給視頻加水印
Android 音視頻編輯經(jīng)驗(yàn)總結(jié)及開源工程分享
Android 音視頻開發(fā)學(xué)習(xí)思路
從開發(fā)小白到音視頻專家
android音視頻開發(fā)基礎(chǔ)4--FFmpeg 入門
視音頻編解碼技術(shù)零基礎(chǔ)學(xué)習(xí)方法
Ijkplayer、ExoPlayer、VLC播放器綜合比較
ijkplayer點(diǎn)播和直播視頻 問(wèn)題 解決及優(yōu)化,視頻播放中可能有的bug
Android視頻編輯器(一)通過(guò)OpenGL預(yù)覽、錄制視頻以及斷點(diǎn)續(xù)錄等
DevYK
cain_huang
Android openGl開發(fā)詳解(二)——通過(guò)SurfaceView,TextureView,GlSurfaceView顯示相機(jī)預(yù)覽(附Demo)
開發(fā)的貓
Android | 音視頻方向進(jìn)階路線及資源合集